You are here

function content_update_6010 in Content Construction Kit (CCK) 6.3

Same name and namespace in other branches
  1. 6.2 content.install \content_update_6010()

Fix multiple serialization caused by per-field to per-type migration. See http://drupal.org/node/407446.

File

./content.install, line 526

Code

function content_update_6010(&$sandbox) {
  if ($abort = content_check_update()) {
    return $abort;
  }
  $ret = array();
  drupal_load('module', 'content');

  // Gather list of tables and columns that need to be updated.
  if (!isset($sandbox['tables'])) {
    $sandbox['tables'] = array();
    $fields = content_fields();
    foreach ($fields as $name => $field) {
      $db_info = content_database_info($field);
      foreach ($db_info['columns'] as $column => $attributes) {
        if (isset($attributes['serialize']) && $attributes['serialize']) {
          $sandbox['tables'][$db_info['table']]['table'] = $db_info['table'];
          $sandbox['tables'][$db_info['table']]['columns'][] = $attributes['column'];
          $sandbox['tables'][$db_info['table']]['multiple'] = $field['multiple'];
        }
      }
    }
    $sandbox['count'] = count($sandbox['tables']);
    $sandbox['current_vid'] = 0;
    $sandbox['current_delta'] = 0;
  }

  // Number of rows to fix in one pass.
  $limit = 500;

  // Start correcting data.
  if ($table_info = array_shift($sandbox['tables'])) {
    $table = $table_info['table'];
    $columns = $table_info['columns'];
    if ($table_info['multiple']) {
      $query = "SELECT * FROM {" . $table . "} WHERE (vid = %d AND delta > %d) OR (vid > %d) ORDER BY vid ASC, delta ASC";
      $args = array(
        $sandbox['current_vid'],
        $sandbox['current_delta'],
        $sandbox['current_vid'],
      );
    }
    else {
      $query = "SELECT * FROM {" . $table . "} WHERE vid > %d ORDER BY vid ASC";
      $args = array(
        $sandbox['current_vid'],
      );
    }
    $result = db_query_range($query, $args, 0, $limit);
    $count = 0;
    while ($row = db_fetch_array($result)) {
      $update_query = $update_args = array();
      foreach ($columns as $column) {
        $data = $row[$column];

        // No need to do anything if the data is NULL.
        if (!empty($data)) {

          // Unserialize until we get something that is not a string
          while (is_string($data)) {
            $unserialized = @unserialize($data);
            if ($unserialized !== FALSE) {
              $data = $unserialized;
            }
            else {

              // TODO : test with a serialized string, just in case...
              break;
            }
          }

          // Re-serialize once.
          $data = serialize($data);

          // If we end up with something different than what we started with, update.
          if ($data !== $row[$column]) {
            $update_query[] = "{$column} = '%s'";
            $update_args[] = $data;
          }
        }
      }
      if ($update_query) {
        $update_args[] = $row['vid'];
        db_query("UPDATE {" . $table . "} SET " . implode(', ', $update_query) . " WHERE vid = %d", $update_args);
      }
      $sandbox['current_vid'] = $row['vid'];
      $sandbox['current_delta'] = isset($row['delta']) ? $row['delta'] : 0;
      $count++;
    }
    if ($count == $limit) {

      // Add the table back into the list of tables to be processed if rows remain.
      array_unshift($sandbox['tables'], $table_info);
    }
    else {

      // Done with this table: reset vid and delta markers.
      $sandbox['current_vid'] = 0;
      $sandbox['current_delta'] = 0;
      $ret[] = array(
        'success' => TRUE,
        'query' => "Fixed serialized values in table {$table}",
      );
    }
  }
  if ($sandbox['count']) {
    $ret['#finished'] = 1 - count($sandbox['tables']) / $sandbox['count'];
  }
  return $ret;
}