Project

General

Profile

Paste
Download (30.2 KB) Statistics
| Branch: | Revision:

root / drupal7 / modules / taxonomy / taxonomy.install @ b0dc3a2e

1
<?php
2

    
3
/**
4
 * @file
5
 * Install, update and uninstall functions for the taxonomy module.
6
 */
7

    
8
/**
9
 * Implements hook_uninstall().
10
 */
11
function taxonomy_uninstall() {
12
  // Remove variables.
13
  variable_del('taxonomy_override_selector');
14
  variable_del('taxonomy_terms_per_page_admin');
15
  // Remove taxonomy_term bundles.
16
  $vocabularies = db_query("SELECT machine_name FROM {taxonomy_vocabulary}")->fetchCol();
17
  foreach ($vocabularies as $vocabulary) {
18
    field_attach_delete_bundle('taxonomy_term', $vocabulary);
19
  }
20
}
21

    
22
/**
23
 * Implements hook_schema().
24
 */
25
function taxonomy_schema() {
26
  $schema['taxonomy_term_data'] = array(
27
    'description' => 'Stores term information.',
28
    'fields' => array(
29
      'tid' => array(
30
        'type' => 'serial',
31
        'unsigned' => TRUE,
32
        'not null' => TRUE,
33
        'description' => 'Primary Key: Unique term ID.',
34
      ),
35
      'vid' => array(
36
        'type' => 'int',
37
        'unsigned' => TRUE,
38
        'not null' => TRUE,
39
        'default' => 0,
40
        'description' => 'The {taxonomy_vocabulary}.vid of the vocabulary to which the term is assigned.',
41
      ),
42
      'name' => array(
43
        'type' => 'varchar',
44
        'length' => 255,
45
        'not null' => TRUE,
46
        'default' => '',
47
        'description' => 'The term name.',
48
        'translatable' => TRUE,
49
      ),
50
      'description' => array(
51
        'type' => 'text',
52
        'not null' => FALSE,
53
        'size' => 'big',
54
        'description' => 'A description of the term.',
55
        'translatable' => TRUE,
56
      ),
57
      'format' => array(
58
        'type' => 'varchar',
59
        'length' => 255,
60
        'not null' => FALSE,
61
        'description' => 'The {filter_format}.format of the description.',
62
      ),
63
      'weight' => array(
64
        'type' => 'int',
65
        'not null' => TRUE,
66
        'default' => 0,
67
        'description' => 'The weight of this term in relation to other terms.',
68
      ),
69
    ),
70
    'primary key' => array('tid'),
71
    'foreign keys' => array(
72
      'vocabulary' => array(
73
        'table' => 'taxonomy_vocabulary',
74
        'columns' => array('vid' => 'vid'),
75
      ),
76
    ),
77
    'indexes' => array(
78
      'taxonomy_tree' => array('vid', 'weight', 'name'),
79
      'vid_name' => array('vid', 'name'),
80
      'name' => array('name'),
81
    ),
82
  );
83

    
84
  $schema['taxonomy_term_hierarchy'] = array(
85
    'description' => 'Stores the hierarchical relationship between terms.',
86
    'fields' => array(
87
      'tid' => array(
88
        'type' => 'int',
89
        'unsigned' => TRUE,
90
        'not null' => TRUE,
91
        'default' => 0,
92
        'description' => 'Primary Key: The {taxonomy_term_data}.tid of the term.',
93
      ),
94
      'parent' => array(
95
        'type' => 'int',
96
        'unsigned' => TRUE,
97
        'not null' => TRUE,
98
        'default' => 0,
99
        'description' => "Primary Key: The {taxonomy_term_data}.tid of the term's parent. 0 indicates no parent.",
100
      ),
101
    ),
102
    'indexes' => array(
103
      'parent' => array('parent'),
104
    ),
105
    'foreign keys' => array(
106
      'taxonomy_term_data' => array(
107
        'table' => 'taxonomy_term_data',
108
        'columns' => array('tid' => 'tid'),
109
      ),
110
    ),
111
    'primary key' => array('tid', 'parent'),
112
  );
113

    
114
  $schema['taxonomy_vocabulary'] = array(
115
    'description' => 'Stores vocabulary information.',
116
    'fields' => array(
117
      'vid' => array(
118
        'type' => 'serial',
119
        'unsigned' => TRUE,
120
        'not null' => TRUE,
121
        'description' => 'Primary Key: Unique vocabulary ID.',
122
      ),
123
      'name' => array(
124
        'type' => 'varchar',
125
        'length' => 255,
126
        'not null' => TRUE,
127
        'default' => '',
128
        'description' => 'Name of the vocabulary.',
129
        'translatable' => TRUE,
130
      ),
131
      'machine_name' => array(
132
        'type' => 'varchar',
133
        'length' => 255,
134
        'not null' => TRUE,
135
        'default' => '',
136
        'description' => 'The vocabulary machine name.',
137
      ),
138
      'description' => array(
139
        'type' => 'text',
140
        'not null' => FALSE,
141
        'size' => 'big',
142
        'description' => 'Description of the vocabulary.',
143
        'translatable' => TRUE,
144
      ),
145
      'hierarchy' => array(
146
        'type' => 'int',
147
        'unsigned' => TRUE,
148
        'not null' => TRUE,
149
        'default' => 0,
150
        'size' => 'tiny',
151
        'description' => 'The type of hierarchy allowed within the vocabulary. (0 = disabled, 1 = single, 2 = multiple)',
152
      ),
153
      'module' => array(
154
        'type' => 'varchar',
155
        'length' => 255,
156
        'not null' => TRUE,
157
        'default' => '',
158
        'description' => 'The module which created the vocabulary.',
159
      ),
160
      'weight' => array(
161
        'type' => 'int',
162
        'not null' => TRUE,
163
        'default' => 0,
164
        'description' => 'The weight of this vocabulary in relation to other vocabularies.',
165
      ),
166
    ),
167
    'primary key' => array('vid'),
168
    'indexes' => array(
169
      'list' => array('weight', 'name'),
170
    ),
171
    'unique keys' => array(
172
      'machine_name' => array('machine_name'),
173
    ),
174
  );
175

    
176
  $schema['taxonomy_index'] = array(
177
    'description' => 'Maintains denormalized information about node/term relationships.',
178
    'fields' => array(
179
      'nid' => array(
180
        'description' => 'The {node}.nid this record tracks.',
181
        'type' => 'int',
182
        'unsigned' => TRUE,
183
        'not null' => TRUE,
184
        'default' => 0,
185
      ),
186
      'tid' => array(
187
         'description' => 'The term ID.',
188
         'type' => 'int',
189
         'unsigned' => TRUE,
190
         'not null' => TRUE,
191
         'default' => 0,
192
      ),
193
      'sticky' => array(
194
        'description' => 'Boolean indicating whether the node is sticky.',
195
        'type' => 'int',
196
        'not null' => FALSE,
197
        'default' => 0,
198
        'size' => 'tiny',
199
      ),
200
      'created' => array(
201
        'description' => 'The Unix timestamp when the node was created.',
202
        'type' => 'int',
203
        'not null' => TRUE,
204
        'default'=> 0,
205
      ),
206
    ),
207
    'indexes' => array(
208
      'term_node' => array('tid', 'sticky', 'created'),
209
      'nid' => array('nid'),
210
    ),
211
    'foreign keys' => array(
212
      'tracked_node' => array(
213
        'table' => 'node',
214
        'columns' => array('nid' => 'nid'),
215
      ),
216
      'term' => array(
217
        'table' => 'taxonomy_term_data',
218
        'columns' => array('tid' => 'tid'),
219
      ),
220
    ),
221
  );
222

    
223
  return $schema;
224
}
225

    
226
/**
227
 * Implements hook_field_schema().
228
 */
229
function taxonomy_field_schema($field) {
230
  return array(
231
    'columns' => array(
232
      'tid' => array(
233
        'type' => 'int',
234
        'unsigned' => TRUE,
235
        'not null' => FALSE,
236
      ),
237
    ),
238
    'indexes' => array(
239
      'tid' => array('tid'),
240
    ),
241
    'foreign keys' => array(
242
      'tid' => array(
243
        'table' => 'taxonomy_term_data',
244
        'columns' => array('tid' => 'tid'),
245
      ),
246
    ),
247
  );
248
}
249

    
250
/**
251
 * Implements hook_update_dependencies().
252
 */
253
function taxonomy_update_dependencies() {
254
  // taxonomy_update_7004() migrates taxonomy term data to fields and therefore
255
  // must run after all Field modules have been enabled, which happens in
256
  // system_update_7027().
257
  $dependencies['taxonomy'][7004] = array(
258
    'system' => 7027,
259
  );
260

    
261
  return $dependencies;
262
}
263

    
264
/**
265
 * Utility function: get the list of vocabularies directly from the database.
266
 *
267
 * This function is valid for a database schema version 7002.
268
 *
269
 * @ingroup update_api
270
 */
271
function _update_7002_taxonomy_get_vocabularies() {
272
  return db_query('SELECT v.* FROM {taxonomy_vocabulary} v ORDER BY v.weight, v.name')->fetchAllAssoc('vid', PDO::FETCH_OBJ);
273
}
274

    
275
/**
276
 * Rename taxonomy tables.
277
 */
278
function taxonomy_update_7001() {
279
  db_rename_table('term_data', 'taxonomy_term_data');
280
  db_rename_table('term_hierarchy', 'taxonomy_term_hierarchy');
281
  db_rename_table('term_node', 'taxonomy_term_node');
282
  db_rename_table('term_relation', 'taxonomy_term_relation');
283
  db_rename_table('term_synonym', 'taxonomy_term_synonym');
284
  db_rename_table('vocabulary', 'taxonomy_vocabulary');
285
  db_rename_table('vocabulary_node_types', 'taxonomy_vocabulary_node_type');
286
}
287

    
288
/**
289
 * Add {vocabulary}.machine_name column.
290
 */
291
function taxonomy_update_7002() {
292
  $field = array(
293
    'type' => 'varchar',
294
    'length' => 255,
295
    'not null' => TRUE,
296
    'default' => '',
297
    'description' => 'The vocabulary machine name.',
298
  );
299

    
300
  db_add_field('taxonomy_vocabulary', 'machine_name', $field);
301

    
302
  // Do a direct query here, rather than calling taxonomy_get_vocabularies(),
303
  // in case Taxonomy module is disabled.
304
  $vids = db_query('SELECT vid FROM {taxonomy_vocabulary}')->fetchCol();
305
  foreach ($vids as $vid) {
306
    $machine_name = 'vocabulary_' . $vid;
307
    db_update('taxonomy_vocabulary')
308
      ->fields(array('machine_name' => $machine_name))
309
      ->condition('vid', $vid)
310
      ->execute();
311
  }
312

    
313
  // The machine_name unique key can only be added after we ensure the
314
  // machine_name column contains unique values.
315
  db_add_unique_key('taxonomy_vocabulary', 'machine_name', array('machine_name'));
316
}
317

    
318
/**
319
 * Remove the related terms setting from vocabularies.
320
 *
321
 * This setting has not been used since Drupal 6. The {taxonomy_relations} table
322
 * itself is retained to allow for data to be upgraded.
323
 */
324
function taxonomy_update_7003() {
325
  db_drop_field('taxonomy_vocabulary', 'relations');
326
}
327

    
328
/**
329
 * Move taxonomy vocabulary associations for nodes to fields and field instances.
330
 */
331
function taxonomy_update_7004() {
332
  $taxonomy_index = array(
333
    'description' => 'Maintains denormalized information about node/term relationships.',
334
    'fields' => array(
335
      'nid' => array(
336
        'description' => 'The {node}.nid this record tracks.',
337
        'type' => 'int',
338
        'unsigned' => TRUE,
339
        'not null' => TRUE,
340
        'default' => 0,
341
      ),
342
      'tid' => array(
343
         'description' => 'The term ID.',
344
         'type' => 'int',
345
         'unsigned' => TRUE,
346
         'not null' => TRUE,
347
         'default' => 0,
348
      ),
349
      'sticky' => array(
350
        'description' => 'Boolean indicating whether the node is sticky.',
351
        'type' => 'int',
352
        'not null' => FALSE,
353
        'default' => 0,
354
        'size' => 'tiny',
355
      ),
356
      'created' => array(
357
        'description' => 'The Unix timestamp when the node was created.',
358
        'type' => 'int',
359
        'unsigned' => TRUE,
360
        'not null' => TRUE,
361
        'default'=> 0,
362
      ),
363
    ),
364
    'indexes' => array(
365
      'term_node' => array('tid', 'sticky', 'created'),
366
      'nid' => array('nid'),
367
    ),
368
    'foreign keys' => array(
369
      'tracked_node' => array(
370
        'table' => 'node',
371
        'columns' => array('nid' => 'nid'),
372
      ),
373
      'term' => array(
374
        'table' => 'taxonomy_term_data',
375
        'columns' => array('tid' => 'tid'),
376
      ),
377
    ),
378
  );
379
  db_create_table('taxonomy_index', $taxonomy_index);
380

    
381
  // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since
382
  // we can no longer rely on $vocabulary->nodes from the API function.
383
  $result = db_query('SELECT v.*, n.type FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid ORDER BY v.weight, v.name');
384
  $vocabularies = array();
385
  foreach ($result as $record) {
386
    // If no node types are associated with a vocabulary, the LEFT JOIN will
387
    // return a NULL value for type.
388
    if (isset($record->type)) {
389
      $node_types[$record->vid][$record->type] = $record->type;
390
      unset($record->type);
391
      $record->nodes = $node_types[$record->vid];
392
    }
393
    elseif (!isset($record->nodes)) {
394
      $record->nodes = array();
395
    }
396
    $vocabularies[$record->vid] = $record;
397
  }
398

    
399
  foreach ($vocabularies as $vocabulary) {
400
    $field_name = 'taxonomy_' . $vocabulary->machine_name;
401
    $field = array(
402
      'field_name' => $field_name,
403
      'module' => 'taxonomy',
404
      'type' => 'taxonomy_term_reference',
405
      'cardinality' => $vocabulary->multiple || $vocabulary->tags ? FIELD_CARDINALITY_UNLIMITED : 1,
406
      'settings' => array(
407
        'required' => $vocabulary->required ? TRUE : FALSE,
408
        'allowed_values' => array(
409
          array(
410
            'vocabulary' => $vocabulary->machine_name,
411
            'parent' => 0,
412
          ),
413
        ),
414
      ),
415
    );
416
    _update_7000_field_create_field($field);
417

    
418
    foreach ($vocabulary->nodes as $bundle) {
419
      $instance = array(
420
        'label' => $vocabulary->name,
421
        'field_name' => $field_name,
422
        'bundle' => $bundle,
423
        'entity_type' => 'node',
424
        'settings' => array(),
425
        'description' => $vocabulary->help,
426
        'required' => $vocabulary->required,
427
        'widget' => array(),
428
        'display' => array(
429
          'default' => array(
430
            'type' => 'taxonomy_term_reference_link',
431
            'weight' => 10,
432
          ),
433
          'teaser' => array(
434
            'type' => 'taxonomy_term_reference_link',
435
            'weight' => 10,
436
          ),
437
        ),
438
      );
439
      if ($vocabulary->tags) {
440
        $instance['widget'] = array(
441
          'type' => 'taxonomy_autocomplete',
442
          'module' => 'taxonomy',
443
          'settings' => array(
444
            'size' => 60,
445
            'autocomplete_path' => 'taxonomy/autocomplete',
446
          ),
447
        );
448
      }
449
      else {
450
        $instance['widget'] = array(
451
          'type' => 'select',
452
          'module' => 'options',
453
          'settings' => array(),
454
        );
455
      }
456
      _update_7000_field_create_instance($field, $instance);
457
    }
458
  }
459

    
460
  // Some contrib projects stored term node associations without regard for the
461
  // selections in the taxonomy_vocabulary_node_types table, or have more terms
462
  // for a single node than the vocabulary allowed. We construct the
463
  // taxonomyextra field to store all the extra stuff.
464

    
465
  // Allowed values for this extra vocabs field is every vocabulary.
466
  $allowed_values = array();
467
  foreach (_update_7002_taxonomy_get_vocabularies() as $vocabulary) {
468
    $allowed_values[] = array(
469
      'vocabulary' => $vocabulary->machine_name,
470
      'parent' => 0,
471
    );
472
  }
473

    
474
  $field_name = 'taxonomyextra';
475
  $field = array(
476
    'field_name' => $field_name,
477
    'module' => 'taxonomy',
478
    'type' => 'taxonomy_term_reference',
479
    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
480
    'settings' => array(
481
      'required' => FALSE,
482
      'allowed_values' => $allowed_values,
483
    ),
484
  );
485
  _update_7000_field_create_field($field);
486

    
487
  foreach (_update_7000_node_get_types() as $bundle) {
488
    $instance = array(
489
      'label' => 'Taxonomy upgrade extras',
490
      'field_name' => $field_name,
491
      'entity_type' => 'node',
492
      'bundle' => $bundle->type,
493
      'settings' => array(),
494
      'description' => 'Debris left over after upgrade from Drupal 6',
495
      'required' => FALSE,
496
      'widget' => array(
497
        'type' => 'taxonomy_autocomplete',
498
        'module' => 'taxonomy',
499
        'settings' => array(),
500
      ),
501
      'display' => array(
502
        'default' => array(
503
          'type' => 'taxonomy_term_reference_link',
504
          'weight' => 10,
505
        ),
506
        'teaser' => array(
507
          'type' => 'taxonomy_term_reference_link',
508
          'weight' => 10,
509
        ),
510
      ),
511
    );
512
    _update_7000_field_create_instance($field, $instance);
513
  }
514

    
515
  $fields = array('help', 'multiple', 'required', 'tags');
516
  foreach ($fields as $field) {
517
    db_drop_field('taxonomy_vocabulary', $field);
518
  }
519
}
520

    
521
/**
522
 * Migrate {taxonomy_term_node} table to field storage.
523
 *
524
 * @todo: This function can possibly be made much faster by wrapping a
525
 * transaction around all the inserts.
526
 */
527
function taxonomy_update_7005(&$sandbox) {
528
  // $sandbox contents:
529
  // - total: The total number of term_node relationships to migrate.
530
  // - count: The number of term_node relationships that have been
531
  //   migrated so far.
532
  // - last: The db_query_range() offset to use when querying
533
  //   term_node; this field is incremented in quantities of $batch
534
  //   (1000) but at the end of each call to this function, last and
535
  //   count are the same.
536
  // - vocabularies: An associative array mapping vocabulary id and node
537
  //   type to field name. If a voc id/node type pair does not appear
538
  //   in this array but a term_node relationship exists mapping a
539
  //   term in voc id to node of that type, the relationship is
540
  //   assigned to the taxonomymyextra field which allows terms of all
541
  //   vocabularies.
542
  // - cursor[values], cursor[deltas]: The contents of $values and
543
  //   $deltas at the end of the previous call to this function. These
544
  //   need to be preserved across calls because a single batch of
545
  //   1000 rows from term_node may end in the middle of the terms for
546
  //   a single node revision.
547
  //
548
  // $values is the array of values about to be/most recently inserted
549
  // into the SQL data table for the taxonomy_term_reference
550
  // field. Before $values is constructed for each record, the
551
  // $values from the previous insert is checked to see if the two
552
  // records are for the same node revision id; this enables knowing
553
  // when to reset the delta counters which are incremented across all
554
  // terms for a single field on a single revision, but reset for each
555
  // new field and revision.
556
  //
557
  // $deltas is an associative array mapping field name to the number
558
  // of term references stored so far for the current revision, which
559
  // provides the delta value for each term reference data insert. The
560
  // deltas are reset for each new revision.
561

    
562
  $conditions = array(
563
    'type' => 'taxonomy_term_reference',
564
    'deleted' => 0,
565
  );
566
  $field_info = _update_7000_field_read_fields($conditions, 'field_name');
567

    
568
  // This is a multi-pass update. On the first call we need to initialize some
569
  // variables.
570
  if (!isset($sandbox['total'])) {
571
    $sandbox['last'] = 0;
572
    $sandbox['count'] = 0;
573

    
574
    // Run the same joins as the query that is used later to retrieve the
575
    // term_node data, this ensures that bad records in that table - for
576
    // tids which aren't in taxonomy_term_data or nids which aren't in {node}
577
    // are not included in the count.
578
    $sandbox['total'] = db_query('SELECT COUNT(*) FROM {taxonomy_term_data} td INNER JOIN {taxonomy_term_node} tn ON td.tid = tn.tid INNER JOIN {node} n ON tn.nid = n.nid LEFT JOIN {node} n2 ON tn.vid = n2.vid')->fetchField();
579

    
580
    // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since
581
    // we can no longer rely on $vocabulary->nodes from the API function.
582
    $result = db_query('SELECT v.vid, v.machine_name, n.type FROM {taxonomy_vocabulary} v INNER JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid');
583
    $vocabularies = array();
584
    foreach ($result as $record) {
585

    
586
      // If no node types are associated with a vocabulary, the LEFT JOIN will
587
      // return a NULL value for type.
588
      if (isset($record->type)) {
589
        $vocabularies[$record->vid][$record->type] = 'taxonomy_'. $record->machine_name;
590
      }
591
    }
592

    
593
    if (!empty($vocabularies)) {
594
      $sandbox['vocabularies'] = $vocabularies;
595
    }
596

    
597
    db_create_table('taxonomy_update_7005', array(
598
      'description' => 'Stores temporary data for taxonomy_update_7005.',
599
      'fields' => array(
600
        'n' => array(
601
          'description' => 'Preserve order.',
602
          'type' => 'serial',
603
          'unsigned' => TRUE,
604
          'not null' => TRUE,
605
        ),
606
        'vocab_id' => array(
607
          'type' => 'int',
608
          'unsigned' => TRUE,
609
          'not null' => TRUE,
610
          'default' => 0,
611
        ),
612
        'tid' => array(
613
          'type' => 'int',
614
          'unsigned' => TRUE,
615
          'not null' => TRUE,
616
        ),
617
        'nid' => array(
618
          'type' => 'int',
619
          'unsigned' => TRUE,
620
          'not null' => TRUE,
621
        ),
622
        'vid' => array(
623
          'type' => 'int',
624
          'unsigned' => TRUE,
625
          'not null' => FALSE,
626
          'default' => NULL,
627
        ),
628
        'type' => array(
629
          'type' => 'varchar',
630
          'length' => 32,
631
          'not null' => TRUE,
632
          'default' => '',
633
        ),
634
        'created' => array(
635
          'type' => 'int',
636
          'not null' => FALSE,
637
        ),
638
        'sticky' => array(
639
          'type' => 'int',
640
          'not null' => FALSE,
641
        ),
642
        'status' => array(
643
          'type' => 'int',
644
          'not null' => FALSE,
645
        ),
646
        'is_current' => array(
647
          'type' => 'int',
648
          'unsigned' => TRUE,
649
          'not null' => FALSE,
650
        ),
651
      ),
652
      'primary key' => array('n'),
653
    ));
654

    
655
    // Query selects all revisions at once and processes them in revision and
656
    // term weight order.
657
    $query = db_select('taxonomy_term_data', 'td');
658
    // We are migrating term-node relationships. If there are none for a
659
    // term, we do not need the term_data row.
660
    $query->join('taxonomy_term_node', 'tn', 'td.tid = tn.tid');
661
    // If a term-node relationship exists for a nid that does not exist, we
662
    // cannot migrate it as we have no node to relate it to; thus we do not
663
    // need that row from term_node.
664
    $query->join('node', 'n', 'tn.nid = n.nid');
665
    // If the current term-node relationship is for the current revision of
666
    // the node, this left join will match and is_current will be non-NULL
667
    // (we also get the current sticky and created in this case). This
668
    // tells us whether to insert into the current data tables in addition
669
    // to the revision data tables.
670
    $query->leftJoin('node', 'n2', 'tn.vid = n2.vid');
671
    $query->addField('td', 'vid', 'vocab_id');
672
    $query->addField('td', 'tid');
673
    $query->addField('tn', 'nid');
674
    $query->addField('tn', 'vid');
675
    $query->addField('n', 'type');
676
    $query->addField('n2', 'created');
677
    $query->addField('n2', 'sticky');
678
    $query->addField('n2', 'status');
679
    $query->addField('n2', 'nid', 'is_current');
680
    // This query must return a consistent ordering across multiple calls.
681
    // We need them ordered by node vid (since we use that to decide when
682
    // to reset the delta counters) and by term weight so they appear
683
    // within each node in weight order. However, tn.vid,td.weight is not
684
    // guaranteed to be unique, so we add tn.tid as an additional sort key
685
    // because tn.tid,tn.vid is the primary key of the D6 term_node table
686
    // and so is guaranteed unique. Unfortunately it also happens to be in
687
    // the wrong order which is less efficient, but c'est la vie.
688
    $query->orderBy('tn.vid');
689
    $query->orderBy('td.weight');
690
    $query->orderBy('tn.tid');
691

    
692
    // Work around a bug in the PostgreSQL driver that would result in fatal
693
    // errors when this subquery is used in the insert query below. See
694
    // https://drupal.org/node/2057693.
695
    $fields = &$query->getFields();
696
    unset($fields['td.weight']);
697
    unset($fields['tn.tid']);
698

    
699
    db_insert('taxonomy_update_7005')
700
      ->from($query)
701
      ->execute();
702
  }
703
  else {
704
    // We do each pass in batches of 1000.
705
    $batch = 1000;
706

    
707
    $result = db_query_range('SELECT vocab_id, tid, nid, vid, type, created, sticky, status, is_current FROM {taxonomy_update_7005} ORDER BY n', $sandbox['last'], $batch);
708
    if (isset($sandbox['cursor'])) {
709
      $values = $sandbox['cursor']['values'];
710
      $deltas = $sandbox['cursor']['deltas'];
711
    }
712
    else {
713
      $deltas = array();
714
    }
715
    foreach ($result as $record) {
716
      $sandbox['count'] += 1;
717

    
718
      // Use the valid field for this vocabulary and node type or use the
719
      // overflow vocabulary if there is no valid field.
720
      $field_name = isset($sandbox['vocabularies'][$record->vocab_id][$record->type]) ? $sandbox['vocabularies'][$record->vocab_id][$record->type] : 'taxonomyextra';
721
      $field = $field_info[$field_name];
722

    
723
      // Start deltas from 0, and increment by one for each term attached to a
724
      // node.
725
      if (!isset($deltas[$field_name])) {
726
        $deltas[$field_name] = 0;
727
      }
728

    
729
      if (isset($values)) {
730

    
731
        // If the last inserted revision_id is the same as the current record,
732
        // use the previous deltas to calculate the next delta.
733
        if ($record->vid == $values[2]) {
734

    
735
          // For limited cardinality fields, the delta must not be allowed to
736
          // exceed the cardinality during the update. So ensure that the
737
          // delta about to be inserted is within this limit.
738
          // @see field_default_validate().
739
          if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ($deltas[$field_name] + 1) > $field['cardinality']) {
740

    
741
            // For excess values of a single-term vocabulary, switch over to
742
            // the overflow field.
743
            $field_name = 'taxonomyextra';
744
            $field = $field_info[$field_name];
745
            if (!isset($deltas[$field_name])) {
746
              $deltas[$field_name] = 0;
747
            }
748
          }
749
        }
750
        else {
751

    
752
          // When the record is a new revision, empty the deltas array.
753
          $deltas = array($field_name => 0);
754
        }
755
      }
756

    
757
      // Table and column found in the field's storage details. During upgrades,
758
      // it's always SQL.
759
      $table_name = "field_data_{$field_name}";
760
      $revision_name = "field_revision_{$field_name}";
761
      $value_column = $field_name . '_tid';
762

    
763
      // Column names and values in field storage are the same for current and
764
      // revision.
765
      $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'language', 'delta', $value_column);
766
      $values = array('node', $record->nid, $record->vid, $record->type, LANGUAGE_NONE, $deltas[$field_name]++, $record->tid);
767

    
768
      // Insert rows into the revision table.
769
      db_insert($revision_name)->fields($columns)->values($values)->execute();
770

    
771
      // is_current column is a node ID if this revision is also current.
772
      if ($record->is_current) {
773
        db_insert($table_name)->fields($columns)->values($values)->execute();
774
        // Only insert a record in the taxonomy index if the node is published.
775
        if ($record->status) {
776
          // Update the {taxonomy_index} table.
777
          db_insert('taxonomy_index')
778
            ->fields(array('nid', 'tid', 'sticky', 'created',))
779
            ->values(array($record->nid, $record->tid, $record->sticky, $record->created))
780
            ->execute();
781
        }
782
      }
783
    }
784

    
785
    // Store the set of inserted values and the current revision's deltas in the
786
    // sandbox.
787
    $sandbox['cursor'] = array(
788
      'values' => $values,
789
      'deltas' => $deltas,
790
    );
791
    $sandbox['last'] += $batch;
792
  }
793

    
794
  if ($sandbox['count'] < $sandbox['total']) {
795
    $sandbox['#finished'] = FALSE;
796
  }
797
  else {
798
    db_drop_table('taxonomy_vocabulary_node_type');
799
    db_drop_table('taxonomy_term_node');
800

    
801
    // If there are no vocabs, we're done.
802
    db_drop_table('taxonomy_update_7005');
803
    $sandbox['#finished'] = TRUE;
804

    
805
    // Determine necessity of taxonomyextras field.
806
    $field = $field_info['taxonomyextra'];
807
    $revision_name = 'field_revision_' . $field['field_name'];
808
    $node_types = db_select($revision_name)->distinct()->fields($revision_name, array('bundle'))
809
      ->execute()->fetchCol();
810

    
811
    if (empty($node_types)) {
812
      // Delete the overflow field if there are no rows in the revision table.
813
      _update_7000_field_delete_field('taxonomyextra');
814
    }
815
    else {
816
      // Remove instances which are not actually used.
817
      $bundles = db_query('SELECT bundle FROM {field_config_instance} WHERE field_name = :field_name', array(':field_name' => 'taxonomyextra'))->fetchCol();
818
      $bundles = array_diff($bundles, $node_types);
819
      foreach ($bundles as $bundle) {
820
        _update_7000_field_delete_instance('taxonomyextra', 'node', $bundle);
821
      }
822
    }
823
  }
824
}
825

    
826
/**
827
 * Add {taxonomy_term_data}.format column.
828
 */
829
function taxonomy_update_7006() {
830
  db_add_field('taxonomy_term_data', 'format', array(
831
    'type' => 'int',
832
    'unsigned' => TRUE,
833
    'not null' => FALSE,
834
    'description' => 'The {filter_format}.format of the description.',
835
  ));
836
}
837

    
838
/**
839
 * Add index on {taxonomy_term_data}.name column to speed up taxonomy_get_term_by_name().
840
 */
841
function taxonomy_update_7007() {
842
  db_add_index('taxonomy_term_data', 'name', array('name'));
843
}
844

    
845
/**
846
 * Change the weight columns to normal int.
847
 */
848
function taxonomy_update_7008() {
849
  db_drop_index('taxonomy_term_data', 'taxonomy_tree');
850
  db_change_field('taxonomy_term_data', 'weight', 'weight', array(
851
    'type' => 'int',
852
    'not null' => TRUE,
853
    'default' => 0,
854
    'description' => 'The weight of this term in relation to other terms.',
855
  ), array(
856
    'indexes' => array(
857
       'taxonomy_tree' => array('vid', 'weight', 'name'),
858
    ),
859
  ));
860

    
861
  db_drop_index('taxonomy_vocabulary', 'list');
862
  db_change_field('taxonomy_vocabulary', 'weight', 'weight', array(
863
    'type' => 'int',
864
    'not null' => TRUE,
865
    'default' => 0,
866
    'description' => 'The weight of this vocabulary in relation to other vocabularies.',
867
  ), array(
868
    'indexes' => array(
869
      'list' => array('weight', 'name'),
870
    ),
871
  ));
872
}
873

    
874
/**
875
 * Change {taxonomy_term_data}.format into varchar.
876
 */
877
function taxonomy_update_7009() {
878
  db_change_field('taxonomy_term_data', 'format', 'format', array(
879
    'type' => 'varchar',
880
    'length' => 255,
881
    'not null' => FALSE,
882
    'description' => 'The {filter_format}.format of the description.',
883
  ));
884
}
885

    
886
/**
887
 * Change {taxonomy_index}.created to support signed int.
888
*/
889
function taxonomy_update_7010() {
890
  db_change_field('taxonomy_index', 'created', 'created', array(
891
    'description' => 'The Unix timestamp when the node was created.',
892
    'type' => 'int',
893
    'unsigned' => FALSE,
894
    'not null' => TRUE,
895
    'default'=> 0,
896
  ));
897
}
898

    
899
/**
900
 * @addtogroup updates-7.x-extra
901
 * @{
902
 */
903

    
904
/**
905
 * Drop unpublished nodes from the index.
906
 */
907
function taxonomy_update_7011(&$sandbox) {
908
  // Initialize information needed by the batch update system.
909
  if (!isset($sandbox['progress'])) {
910
    $sandbox['progress'] = 0;
911
    $sandbox['max'] = db_query('SELECT COUNT(DISTINCT n.nid) FROM {node} n INNER JOIN {taxonomy_index} t ON n.nid = t.nid WHERE n.status = :status', array(':status' => NODE_NOT_PUBLISHED))->fetchField();
912
    // If there's no data, don't bother with the extra work.
913
    if (empty($sandbox['max'])) {
914
      return;
915
    }
916
  }
917

    
918
  // Process records in groups of 5000.
919
  $limit = 5000;
920
  $nids = db_query_range('SELECT DISTINCT n.nid FROM {node} n INNER JOIN {taxonomy_index} t ON n.nid = t.nid WHERE n.status = :status', 0, $limit, array(':status' => NODE_NOT_PUBLISHED))->fetchCol();
921
  if (!empty($nids)) {
922
    db_delete('taxonomy_index')
923
      ->condition('nid', $nids)
924
      ->execute();
925
  }
926

    
927
  // Update our progress information for the batch update.
928
  $sandbox['progress'] += $limit;
929

    
930
  // Indicate our current progress to the batch update system, if the update is
931
  // not yet complete.
932
  if ($sandbox['progress'] < $sandbox['max']) {
933
    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
934
  }
935
}
936

    
937
/**
938
 * @} End of "addtogroup updates-7.x-extra".
939
 */