comparison modules/taxonomy/taxonomy.install @ 0:ff03f76ab3fe

initial version
author danieleb <danielebarchiesi@me.com>
date Wed, 21 Aug 2013 18:51:11 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:ff03f76ab3fe
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 'is_current' => array(
642 'type' => 'int',
643 'unsigned' => TRUE,
644 'not null' => FALSE,
645 ),
646 ),
647 'primary key' => array('n'),
648 ));
649
650 // Query selects all revisions at once and processes them in revision and
651 // term weight order.
652 $query = db_select('taxonomy_term_data', 'td');
653 // We are migrating term-node relationships. If there are none for a
654 // term, we do not need the term_data row.
655 $query->join('taxonomy_term_node', 'tn', 'td.tid = tn.tid');
656 // If a term-node relationship exists for a nid that does not exist, we
657 // cannot migrate it as we have no node to relate it to; thus we do not
658 // need that row from term_node.
659 $query->join('node', 'n', 'tn.nid = n.nid');
660 // If the current term-node relationship is for the current revision of
661 // the node, this left join will match and is_current will be non-NULL
662 // (we also get the current sticky and created in this case). This
663 // tells us whether to insert into the current data tables in addition
664 // to the revision data tables.
665 $query->leftJoin('node', 'n2', 'tn.vid = n2.vid');
666 $query->addField('td', 'vid', 'vocab_id');
667 $query->addField('td', 'tid');
668 $query->addField('tn', 'nid');
669 $query->addField('tn', 'vid');
670 $query->addField('n', 'type');
671 $query->addField('n2', 'created');
672 $query->addField('n2', 'sticky');
673 $query->addField('n2', 'nid', 'is_current');
674 // This query must return a consistent ordering across multiple calls.
675 // We need them ordered by node vid (since we use that to decide when
676 // to reset the delta counters) and by term weight so they appear
677 // within each node in weight order. However, tn.vid,td.weight is not
678 // guaranteed to be unique, so we add tn.tid as an additional sort key
679 // because tn.tid,tn.vid is the primary key of the D6 term_node table
680 // and so is guaranteed unique. Unfortunately it also happens to be in
681 // the wrong order which is less efficient, but c'est la vie.
682 $query->orderBy('tn.vid');
683 $query->orderBy('td.weight');
684 $query->orderBy('tn.tid');
685
686 // Work around a bug in the PostgreSQL driver that would result in fatal
687 // errors when this subquery is used in the insert query below. See
688 // https://drupal.org/node/2057693.
689 $fields = &$query->getFields();
690 unset($fields['td.weight']);
691 unset($fields['tn.tid']);
692
693 db_insert('taxonomy_update_7005')
694 ->from($query)
695 ->execute();
696 }
697 else {
698 // We do each pass in batches of 1000.
699 $batch = 1000;
700
701 $result = db_query_range('SELECT vocab_id, tid, nid, vid, type, created, sticky, is_current FROM {taxonomy_update_7005} ORDER BY n', $sandbox['last'], $batch);
702 if (isset($sandbox['cursor'])) {
703 $values = $sandbox['cursor']['values'];
704 $deltas = $sandbox['cursor']['deltas'];
705 }
706 else {
707 $deltas = array();
708 }
709 foreach ($result as $record) {
710 $sandbox['count'] += 1;
711
712 // Use the valid field for this vocabulary and node type or use the
713 // overflow vocabulary if there is no valid field.
714 $field_name = isset($sandbox['vocabularies'][$record->vocab_id][$record->type]) ? $sandbox['vocabularies'][$record->vocab_id][$record->type] : 'taxonomyextra';
715 $field = $field_info[$field_name];
716
717 // Start deltas from 0, and increment by one for each term attached to a
718 // node.
719 if (!isset($deltas[$field_name])) {
720 $deltas[$field_name] = 0;
721 }
722
723 if (isset($values)) {
724
725 // If the last inserted revision_id is the same as the current record,
726 // use the previous deltas to calculate the next delta.
727 if ($record->vid == $values[2]) {
728
729 // For limited cardinality fields, the delta must not be allowed to
730 // exceed the cardinality during the update. So ensure that the
731 // delta about to be inserted is within this limit.
732 // @see field_default_validate().
733 if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ($deltas[$field_name] + 1) > $field['cardinality']) {
734
735 // For excess values of a single-term vocabulary, switch over to
736 // the overflow field.
737 $field_name = 'taxonomyextra';
738 $field = $field_info[$field_name];
739 if (!isset($deltas[$field_name])) {
740 $deltas[$field_name] = 0;
741 }
742 }
743 }
744 else {
745
746 // When the record is a new revision, empty the deltas array.
747 $deltas = array($field_name => 0);
748 }
749 }
750
751 // Table and column found in the field's storage details. During upgrades,
752 // it's always SQL.
753 $table_name = "field_data_{$field_name}";
754 $revision_name = "field_revision_{$field_name}";
755 $value_column = $field_name . '_tid';
756
757 // Column names and values in field storage are the same for current and
758 // revision.
759 $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'language', 'delta', $value_column);
760 $values = array('node', $record->nid, $record->vid, $record->type, LANGUAGE_NONE, $deltas[$field_name]++, $record->tid);
761
762 // Insert rows into the revision table.
763 db_insert($revision_name)->fields($columns)->values($values)->execute();
764
765 // is_current column is a node ID if this revision is also current.
766 if ($record->is_current) {
767 db_insert($table_name)->fields($columns)->values($values)->execute();
768
769 // Update the {taxonomy_index} table.
770 db_insert('taxonomy_index')
771 ->fields(array('nid', 'tid', 'sticky', 'created',))
772 ->values(array($record->nid, $record->tid, $record->sticky, $record->created))
773 ->execute();
774 }
775 }
776
777 // Store the set of inserted values and the current revision's deltas in the
778 // sandbox.
779 $sandbox['cursor'] = array(
780 'values' => $values,
781 'deltas' => $deltas,
782 );
783 $sandbox['last'] += $batch;
784 }
785
786 if ($sandbox['count'] < $sandbox['total']) {
787 $sandbox['#finished'] = FALSE;
788 }
789 else {
790 db_drop_table('taxonomy_vocabulary_node_type');
791 db_drop_table('taxonomy_term_node');
792
793 // If there are no vocabs, we're done.
794 db_drop_table('taxonomy_update_7005');
795 $sandbox['#finished'] = TRUE;
796
797 // Determine necessity of taxonomyextras field.
798 $field = $field_info['taxonomyextra'];
799 $revision_name = 'field_revision_' . $field['field_name'];
800 $node_types = db_select($revision_name)->distinct()->fields($revision_name, array('bundle'))
801 ->execute()->fetchCol();
802
803 if (empty($node_types)) {
804 // Delete the overflow field if there are no rows in the revision table.
805 _update_7000_field_delete_field('taxonomyextra');
806 }
807 else {
808 // Remove instances which are not actually used.
809 $bundles = db_query('SELECT bundle FROM {field_config_instance} WHERE field_name = :field_name', array(':field_name' => 'taxonomyextra'))->fetchCol();
810 $bundles = array_diff($bundles, $node_types);
811 foreach ($bundles as $bundle) {
812 _update_7000_field_delete_instance('taxonomyextra', 'node', $bundle);
813 }
814 }
815 }
816 }
817
818 /**
819 * Add {taxonomy_term_data}.format column.
820 */
821 function taxonomy_update_7006() {
822 db_add_field('taxonomy_term_data', 'format', array(
823 'type' => 'int',
824 'unsigned' => TRUE,
825 'not null' => FALSE,
826 'description' => 'The {filter_format}.format of the description.',
827 ));
828 }
829
830 /**
831 * Add index on {taxonomy_term_data}.name column to speed up taxonomy_get_term_by_name().
832 */
833 function taxonomy_update_7007() {
834 db_add_index('taxonomy_term_data', 'name', array('name'));
835 }
836
837 /**
838 * Change the weight columns to normal int.
839 */
840 function taxonomy_update_7008() {
841 db_drop_index('taxonomy_term_data', 'taxonomy_tree');
842 db_change_field('taxonomy_term_data', 'weight', 'weight', array(
843 'type' => 'int',
844 'not null' => TRUE,
845 'default' => 0,
846 'description' => 'The weight of this term in relation to other terms.',
847 ), array(
848 'indexes' => array(
849 'taxonomy_tree' => array('vid', 'weight', 'name'),
850 ),
851 ));
852
853 db_drop_index('taxonomy_vocabulary', 'list');
854 db_change_field('taxonomy_vocabulary', 'weight', 'weight', array(
855 'type' => 'int',
856 'not null' => TRUE,
857 'default' => 0,
858 'description' => 'The weight of this vocabulary in relation to other vocabularies.',
859 ), array(
860 'indexes' => array(
861 'list' => array('weight', 'name'),
862 ),
863 ));
864 }
865
866 /**
867 * Change {taxonomy_term_data}.format into varchar.
868 */
869 function taxonomy_update_7009() {
870 db_change_field('taxonomy_term_data', 'format', 'format', array(
871 'type' => 'varchar',
872 'length' => 255,
873 'not null' => FALSE,
874 'description' => 'The {filter_format}.format of the description.',
875 ));
876 }
877
878 /**
879 * Change {taxonomy_index}.created to support signed int.
880 */
881 function taxonomy_update_7010() {
882 db_change_field('taxonomy_index', 'created', 'created', array(
883 'description' => 'The Unix timestamp when the node was created.',
884 'type' => 'int',
885 'unsigned' => FALSE,
886 'not null' => TRUE,
887 'default'=> 0,
888 ));
889 }
890