You are here

function content_alter_db_field in Content Construction Kit (CCK) 5

Perform adds, alters, and drops as needed to synchronize the database with new field definitions.

13 calls to content_alter_db_field()
content_field_instance_delete in ./content_crud.inc
Delete an existing field instance.
content_update_10 in ./content.install
Fix corrupted db due to a bug in 1.3 release (http://drupal.org/node/115332)
content_update_1004 in ./content.install
Fix corrupted db due to a bug in 1.3 release (http://drupal.org/node/115332)
content_update_5 in ./content.install
Move data from per-field storage to per-content-type storage where possible.
nodereference_update_3 in ./nodereference.install
Data is now stored in per-field tables.

... See full list

File

./content_admin.inc, line 1081
Administrative interface for content type creation.

Code

function content_alter_db_field($previous_field, $previous_columns, $new_field, $new_columns) {

  // When adding and removing columns, we need to know what content type has an instance of the field.
  if (count($previous_columns)) {
    if (!isset($previous_field['type_name'])) {
      $previous_field['type_name'] = db_result(db_query("SELECT type_name FROM {node_field_instance} WHERE field_name = '%s'", $previous_field['field_name']));
    }
    $previous_db_info = content_database_info($previous_field);
  }
  if (count($new_columns)) {
    $new_field['type_name'] = db_result(db_query("SELECT type_name FROM {node_field_instance} WHERE field_name = '%s'", $new_field['field_name']));
    $new_db_info = content_database_info($new_field);
  }
  if (!count($new_columns)) {
    if (count($previous_columns)) {
      if ($previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) {
        db_query('DROP TABLE {' . $previous_db_info['table'] . '}');
      }
      else {
        foreach ($previous_db_info['columns'] as $column => $attributes) {
          db_query('ALTER TABLE {' . $previous_db_info['table'] . '} DROP ' . $attributes['column']);
        }
      }
    }
    return;
  }
  if ($new_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) {
    if (!count($previous_columns) || $previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE) {

      // New columns with per-field storage; need to add a table.
      if ($new_field['multiple']) {
        switch ($GLOBALS['db_type']) {
          case 'mysql':
          case 'mysqli':
            db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                vid int unsigned NOT NULL default '0',\n                delta int unsigned NOT NULL default '0',\n                nid int unsigned NOT NULL default '0',\n                PRIMARY KEY (vid,delta),\n                KEY nid (nid)\n              ) /*!40100 DEFAULT CHARACTER SET utf8 */");
            break;
          case 'pgsql':
            db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                vid int_unsigned NOT NULL default '0',\n                delta int_unsigned NOT NULL default '0',\n                nid int_unsigned NOT NULL default '0',\n                PRIMARY KEY (vid,delta)\n              )");
            db_query("CREATE INDEX {" . $new_db_info['table'] . "}_nid_idx ON {" . $new_db_info['table'] . "}(nid)");
            break;
        }
      }
      else {
        switch ($GLOBALS['db_type']) {
          case 'mysql':
          case 'mysqli':
            db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                vid int unsigned NOT NULL default '0',\n                nid int unsigned NOT NULL default '0',\n                PRIMARY KEY (vid),\n                KEY nid (nid)\n              ) /*!40100 DEFAULT CHARACTER SET utf8 */");
            break;
          case 'pgsql':
            db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                vid int_unsigned NOT NULL default '0',\n                nid int_unsigned NOT NULL default '0',\n                PRIMARY KEY (vid)\n              )");
            db_query("CREATE INDEX {" . $new_db_info['table'] . "}_nid_idx ON {" . $new_db_info['table'] . "}(nid)");
            break;
        }
      }
    }
    if (count($previous_columns) && $previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) {

      // Already using per-field storage; change multiplicity if needed.
      if ($previous_field['multiple'] && !$new_field['multiple']) {
        db_query('DELETE FROM {' . $new_db_info['table'] . '} WHERE delta != 0');
        db_query('ALTER TABLE {' . $new_db_info['table'] . '} DROP delta');
        switch ($GLOBALS['db_type']) {
          case 'mysql':
          case 'mysqli':
            db_query('ALTER TABLE {' . $new_db_info['table'] . '} DROP PRIMARY KEY');
            db_query('ALTER TABLE {' . $new_db_info['table'] . '} ADD PRIMARY KEY (vid)');
            break;
          case 'pgsql':
            db_query('ALTER TABLE {' . $new_db_info['table'] . '} DROP CONSTRAINT {' . $new_db_info['table'] . '}_pkey');
            db_query('ALTER TABLE {' . $new_db_info['table'] . '} ADD PRIMARY KEY (vid)');
            break;
        }
      }
      else {
        if (!$previous_field['multiple'] && $new_field['multiple']) {
          content_db_add_column($new_db_info['table'], 'delta', 'int', array(
            'unsigned' => TRUE,
            'not null' => TRUE,
            'default' => 0,
          ));
          switch ($GLOBALS['db_type']) {
            case 'mysql':
            case 'mysqli':
              db_query('ALTER TABLE {' . $new_db_info['table'] . '} DROP PRIMARY KEY');
              db_query('ALTER TABLE {' . $new_db_info['table'] . '} ADD PRIMARY KEY (vid,delta)');
              break;
            case 'pgsql':
              db_query('ALTER TABLE {' . $new_db_info['table'] . '} DROP CONSTRAINT {' . $new_db_info['table'] . '}_pkey');
              db_query('ALTER TABLE {' . $new_db_info['table'] . '} ADD PRIMARY KEY (vid,delta)');
              break;
          }
        }
      }
    }
  }

  // Add new columns and change modified columns.
  foreach ($new_columns as $column => $attributes) {
    $column_name = $new_field['field_name'] . '_' . $column;
    if (!isset($previous_columns[$column]) || $previous_field['db_storage'] != $new_field['db_storage']) {
      if (!db_table_exists($new_db_info['table'])) {
        if ($new_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE) {
          if ($new_field['multiple']) {
            switch ($GLOBALS['db_type']) {
              case 'mysql':
              case 'mysqli':
                db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                  vid int unsigned NOT NULL default '0',\n                  delta int unsigned NOT NULL default '0',\n                  nid int unsigned NOT NULL default '0',\n                  PRIMARY KEY (vid,delta),\n                  KEY nid (nid)\n                ) /*!40100 DEFAULT CHARACTER SET utf8 */");
                break;
              case 'pgsql':
                db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                  vid int_unsigned NOT NULL default '0',\n                  delta int_unsigned NOT NULL default '0',\n                  nid int_unsigned NOT NULL default '0',\n                  PRIMARY KEY (vid,delta)\n                )");
                db_query("CREATE INDEX {" . $new_db_info['table'] . "}_nid_idx ON {" . $new_db_info['table'] . "}(nid)");
                break;
            }
          }
          else {
            switch ($GLOBALS['db_type']) {
              case 'mysql':
              case 'mysqli':
                db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                  vid int unsigned NOT NULL default '0',\n                  nid int unsigned NOT NULL default '0',\n                  PRIMARY KEY (vid),\n                  KEY nid (nid)\n                ) /*!40100 DEFAULT CHARACTER SET utf8 */");
                break;
              case 'pgsql':
                db_query("CREATE TABLE {" . $new_db_info['table'] . "} (\n                    vid int_unsigned NOT NULL default '0',\n                    nid int_unsigned NOT NULL default '0',\n                    PRIMARY KEY (vid)\n                  )");
                db_query("CREATE INDEX {" . $new_db_info['table'] . "}_nid_idx ON {" . $new_db_info['table'] . "}(nid)");
                break;
            }
          }

          // end: if ($new_field['multiple'])
        }

        // end: if ($new_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE)
      }
      content_db_add_column($new_db_info['table'], $column_name, $attributes['type'], $attributes);
    }
    else {
      if ($attributes != $previous_columns[$column]) {
        content_db_change_column($new_db_info['table'], $column_name, $column_name, $attributes['type'], $attributes);
      }
    }
  }
  if (count($previous_columns) && count($new_columns)) {

    // Remove obsolete columns.
    foreach ($previous_columns as $column => $attributes) {
      $column_name = $previous_field['field_name'] . '_' . $column;
      if (!isset($new_columns[$column])) {
        db_query('ALTER TABLE {' . $new_db_info['table'] . '} DROP ' . $column_name);
      }
    }

    // Migrate data from one storage type to another
    // We check if the previous table still exists (avoid problems during upgrades from older db schemes)
    if (db_table_exists($previous_db_info['table'])) {

      // Migrate data from per-content-type storage.
      if ($previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE && $new_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) {
        $columns = array();
        foreach ($previous_db_info['columns'] as $column => $attributes) {
          $columns[] = $attributes['column'];
        }
        if ($new_field['multiple']) {
          db_query('INSERT INTO {' . $new_db_info['table'] . '} (vid, nid, delta, ' . implode(', ', $columns) . ') SELECT vid, nid, 0, ' . implode(', ', $columns) . ' FROM {' . $previous_db_info['table'] . '}');
        }
        else {
          db_query('INSERT INTO {' . $new_db_info['table'] . '} (vid, nid, ' . implode(', ', $columns) . ') SELECT vid, nid, ' . implode(', ', $columns) . ' FROM {' . $previous_db_info['table'] . '}');
        }
        foreach ($columns as $column_name) {
          db_query('ALTER TABLE {' . $previous_db_info['table'] . '} DROP ' . $column_name);
        }
      }

      // Migrate data from per-field storage.
      if ($previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD && $new_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE) {
        $column_names = array();
        $column_placeholders_default = array();
        $column_assignments_default = array();
        foreach ($new_db_info['columns'] as $column => $attributes) {
          $column_names[] = $attributes['column'];
          if (in_array($attributes['type'], array(
            'int',
            'mediumint',
            'tinyint',
            'bigint',
            'float',
          ))) {
            $column_placeholders_default[] = '%d';
            $column_assignments_default[] = $attributes['column'] . ' = %d';
          }
          else {
            $column_placeholders_default[] = "'%s'";
            $column_assignments_default[] = $attributes['column'] . " = '%s'";
          }
        }
        if ($previous_field['multiple']) {
          $result = db_query("SELECT " . implode(', ', $column_names) . ", c.vid, c.nid FROM {" . $previous_db_info['table'] . "} c JOIN {node} n ON c.nid = n.nid WHERE delta = 0 AND n.type = '%s'", $new_field['type_name']);
        }
        else {
          $result = db_query("SELECT " . implode(', ', $column_names) . ", c.vid, c.nid FROM {" . $previous_db_info['table'] . "} c JOIN {node} n ON c.nid = n.nid WHERE n.type = '%s'", $new_field['type_name']);
        }
        while ($data = db_fetch_array($result)) {
          $column_assignments = $column_assignments_default;
          $column_placeholders = $column_placeholders_default;

          // search for NULL values and replace assignments and placeholders accordingly
          foreach ($data as $key => $value) {
            if (is_null($value)) {
              $pos = array_search($key, $column_names);
              $column_assignments[$pos] = $key . "= %s";
              $column_placeholders[$pos] = "%s";
              $data[$key] = 'NULL';
            }
          }
          if (db_result(db_query('SELECT COUNT(*) FROM {' . $new_db_info['table'] . '} WHERE vid = %d AND nid = %d', $data['vid'], $data['nid']))) {
            db_query('UPDATE {' . $new_db_info['table'] . '} SET ' . implode(', ', $column_assignments) . ' WHERE vid = %d AND nid = %d', $data);
          }
          else {
            db_query('INSERT INTO {' . $new_db_info['table'] . '} (' . implode(', ', $column_names) . ', vid, nid) VALUES (' . implode(', ', $column_placeholders) . ', %d, %d)', $data);
          }
        }
        db_query('DROP TABLE {' . $previous_db_info['table'] . '}');
      }
    }
  }
}