function content_alter_db in Content Construction Kit (CCK) 6
Same name and namespace in other branches
- 6.3 includes/content.admin.inc \content_alter_db()
- 6.2 includes/content.admin.inc \content_alter_db()
Perform adds, alters, and drops as needed to synchronize the database with new field definitions.
2 calls to content_alter_db()
- content_alter_fields in includes/
content.admin.inc - Batching process for changing the field schema, running each affected node through node_save() first, to fire all hooks.
- content_alter_schema in includes/
content.admin.inc - Content Schema Alter
1 string reference to 'content_alter_db'
- content_alter_fields in includes/
content.admin.inc - Batching process for changing the field schema, running each affected node through node_save() first, to fire all hooks.
File
- includes/
content.admin.inc, line 1020 - Administrative interface for content type creation.
Code
function content_alter_db($previous_field, $new_field) {
$ret = array();
// One or the other of these must be valid.
if (empty($previous_field) && empty($new_field)) {
return $ret;
}
// Gather relevant information : schema, table name...
$previous_schema = !empty($previous_field) ? content_table_schema($previous_field) : array();
$new_schema = !empty($new_field) ? content_table_schema($new_field) : array();
if (!empty($previous_field)) {
$previous_db_info = content_database_info($previous_field);
$previous_table = $previous_db_info['table'];
}
if (!empty($new_field)) {
$new_db_info = content_database_info($new_field);
$new_table = $new_db_info['table'];
}
// Deleting this field entirely is a simple case.
if (empty($new_field)) {
if ($previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) {
db_drop_table($ret, $previous_table);
}
else {
foreach ($previous_schema['fields'] as $column => $attributes) {
if (!in_array($column, array(
'nid',
'vid',
'delta',
))) {
db_drop_field($ret, $previous_table, $column);
}
}
}
return content_alter_db_cleanup($ret);
}
// All content types that have fields need a content type table.
if (!empty($new_field)) {
$base_tablename = _content_tablename($new_field['type_name'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE);
if (!db_table_exists($base_tablename)) {
db_create_table($ret, $base_tablename, content_table_schema());
}
}
// Create new table and columns, if not already created.
if (!db_table_exists($new_table)) {
db_create_table($ret, $new_table, $new_schema);
}
else {
// Or add fields to an existing table.
foreach ($new_schema['fields'] as $column => $attributes) {
if (!in_array($column, array(
'nid',
'vid',
'delta',
)) && !db_column_exists($new_table, $column)) {
db_add_field($ret, $new_table, $column, $attributes);
}
}
}
// If this is a new field, we're done.
if (empty($previous_field)) {
return content_alter_db_cleanup($ret);
}
// If the previous table doesn't exist, we're done.
// Could happen if someone tries to run a schema update from an
// content.install update function more than once.
if (!db_table_exists($previous_table)) {
return content_alter_db_cleanup($ret);
}
// If changing data from one schema to another, see if changes require that
// we drop multiple values or migrate data from one storage type to another.
$migrate_columns = array_intersect_assoc($new_schema['fields'], $previous_schema['fields']);
unset($migrate_columns['nid'], $migrate_columns['vid'], $migrate_columns['delta']);
// If we're going from one multiple value a smaller one or to single,
// drop all delta values higher than the new maximum delta value.
// Not needed if the new multiple is unlimited or if the new table is the content table.
if ($new_table != $base_tablename && $new_field['multiple'] < $previous_field['multiple'] && $new_field['multiple'] != 1) {
db_query("DELETE FROM {" . $new_table . "} WHERE delta >= " . max(1, $new_field['multiple']));
}
// If going from multiple to non-multiple, make sure the field tables have
// the right database structure to accept migrated data.
if ($new_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) {
if ($previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD && count($previous_schema['fields'])) {
// Already using per-field storage; change multiplicity if needed.
if ($previous_field['multiple'] > 0 && $new_field['multiple'] == 0) {
db_drop_field($ret, $new_table, 'delta');
db_drop_primary_key($ret, $new_table);
db_add_primary_key($ret, $new_table, array(
'vid',
));
}
else {
if ($previous_field['multiple'] == 0 && $new_field['multiple'] > 0) {
db_add_field($ret, $new_table, 'delta', array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
));
db_drop_primary_key($ret, $new_table);
db_add_primary_key($ret, $new_table, array(
'vid',
'delta',
));
}
}
}
}
// 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_keys($migrate_columns);
if ($new_field['multiple']) {
db_query('INSERT INTO {' . $new_table . '} (vid, nid, delta, ' . implode(', ', $columns) . ') ' . ' SELECT vid, nid, 0, ' . implode(', ', $columns) . ' FROM {' . $previous_table . '}');
}
else {
db_query('INSERT INTO {' . $new_table . '} (vid, nid, ' . implode(', ', $columns) . ') ' . ' SELECT vid, nid, ' . implode(', ', $columns) . ' FROM {' . $previous_table . '}');
}
foreach ($columns as $column_name) {
db_drop_field($ret, $previous_table, $column_name);
}
}
// Migrate data from per-field storage, and drop per-field table.
if ($previous_field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD && $new_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE) {
// In order to be able to use drupal_write_record, we need to
// rebuild the schema now.
content_alter_db_cleanup($ret);
if ($previous_field['multiple']) {
$result = db_query("SELECT * FROM {" . $previous_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 * FROM {" . $previous_table . "} c JOIN {node} n ON c.nid = n.nid WHERE n.type = '%s'", $new_field['type_name']);
}
$record = array();
while ($data = db_fetch_array($result)) {
$record['nid'] = $data['nid'];
$record['vid'] = $data['vid'];
if ($previous_field['multiple']) {
$record['delta'] = $data['delta'];
}
foreach ($migrate_columns as $column => $attributes) {
$record[$column] = is_null($data[$column]) ? NULL : $data[$column];
}
if (db_result(db_query('SELECT COUNT(*) FROM {' . $new_table . '} WHERE vid = %d AND nid = %d', $data['vid'], $data['nid']))) {
$keys = $new_field['multiple'] ? array(
'vid',
'delta',
) : array(
'vid',
);
drupal_write_record($new_table, $record, $keys);
}
else {
drupal_write_record($new_table, $record);
}
}
db_drop_table($ret, $previous_table);
}
// Change modified columns that don't involve storage changes.
foreach ($new_schema['fields'] as $column => $attributes) {
if (isset($previous_schema['fields'][$column]) && $previous_field['db_storage'] == $new_field['db_storage']) {
if ($attributes != $previous_schema['fields'][$column]) {
if (!in_array($column, array(
'nid',
'vid',
'delta',
))) {
db_change_field($ret, $new_table, $column, $column, $attributes);
}
}
}
}
// Remove obsolete columns.
foreach ($previous_schema['fields'] as $column => $attributes) {
if (!isset($new_schema['fields'][$column])) {
if (!in_array($column, array(
'nid',
'vid',
'delta',
))) {
db_drop_field($ret, $previous_table, $column);
}
}
}
// TODO : debugging stuff - should be removed
if (module_exists('devel')) {
//dsm($ret);
}
return $ret;
}