Project

General

Profile

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

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

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
      'widget' => array(
496
        'type' => 'taxonomy_autocomplete',
497
        'module' => 'taxonomy',
498
        'settings' => array(),
499
      ),
500
      'display' => array(
501
        'default' => array(
502
          'type' => 'taxonomy_term_reference_link',
503
          'weight' => 10,
504
        ),
505
        'teaser' => array(
506
          'type' => 'taxonomy_term_reference_link',
507
          'weight' => 10,
508
        ),
509
      ),
510
    );
511
    _update_7000_field_create_instance($field, $instance);
512
  }
513

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

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

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

    
573
    // Run the same joins as the query that is used later to retrieve the
574
    // term_node data, this ensures that bad records in that table - for
575
    // tids which aren't in taxonomy_term_data or nids which aren't in {node}
576
    // are not included in the count.
577
    $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();
578

    
579
    // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since
580
    // we can no longer rely on $vocabulary->nodes from the API function.
581
    $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');
582
    $vocabularies = array();
583
    foreach ($result as $record) {
584

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

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

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

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

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

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

    
706
    $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);
707
    if (isset($sandbox['cursor'])) {
708
      $values = $sandbox['cursor']['values'];
709
      $deltas = $sandbox['cursor']['deltas'];
710
    }
711
    else {
712
      $deltas = array();
713
    }
714
    foreach ($result as $record) {
715
      $sandbox['count'] += 1;
716

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

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

    
728
      if (isset($values)) {
729

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
903
/**
904
 * Drop unpublished nodes from the index.
905
 */
906
function taxonomy_update_7011(&$sandbox) {
907
  // Initialize information needed by the batch update system.
908
  if (!isset($sandbox['progress'])) {
909
    $sandbox['progress'] = 0;
910
    $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();
911
    // If there's no data, don't bother with the extra work.
912
    if (empty($sandbox['max'])) {
913
      return;
914
    }
915
  }
916

    
917
  // Process records in groups of 5000.
918
  $limit = 5000;
919
  $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();
920
  if (!empty($nids)) {
921
    db_delete('taxonomy_index')
922
      ->condition('nid', $nids)
923
      ->execute();
924
  }
925

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

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

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