commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / modules / taxonomy / taxonomy.install
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 */