function update_structure($verbose, $action) { global $a, $db; $errors = false; logger('updating structure', LOGGER_DEBUG); // Get the current structure $database = array(); $tables = q("show tables"); foreach ($tables as $table) { $table = current($table); $database[$table] = table_structure($table); } // Get the definition $definition = db_definition(); // Compare it foreach ($definition as $name => $structure) { $sql3 = ""; if (!isset($database[$name])) { $r = db_create_table($name, $structure["fields"], $verbose, $action); if (false === $r) { $errors .= t('Errors encountered creating database tables.') . $name . EOL; } } else { // Drop the index if it isn't present in the definition foreach ($database[$name]["indexes"] as $indexname => $fieldnames) { if (!isset($structure["indexes"][$indexname])) { $sql2 = db_drop_index($indexname); if ($sql3 == "") { $sql3 = "ALTER TABLE `" . $name . "` " . $sql2; } else { $sql3 .= ", " . $sql2; } } } // Compare the field structure field by field foreach ($structure["fields"] as $fieldname => $parameters) { if (!isset($database[$name]["fields"][$fieldname])) { $sql2 = db_add_table_field($fieldname, $parameters); if ($sql3 == "") { $sql3 = "ALTER TABLE `" . $name . "` " . $sql2; } else { $sql3 .= ", " . $sql2; } } else { // Compare the field definition $current_field_definition = implode(",", $database[$name]["fields"][$fieldname]); $new_field_definition = implode(",", $parameters); if ($current_field_definition != $new_field_definition) { $sql2 = db_modify_table_field($fieldname, $parameters); if ($sql3 == "") { $sql3 = "ALTER TABLE `" . $name . "` " . $sql2; } else { $sql3 .= ", " . $sql2; } } } } } // Create the index foreach ($structure["indexes"] as $indexname => $fieldnames) { if (!isset($database[$name]["indexes"][$indexname])) { $sql2 = db_create_index($indexname, $fieldnames); if ($sql2 != "") { if ($sql3 == "") { $sql3 = "ALTER TABLE `" . $name . "` " . $sql2; } else { $sql3 .= ", " . $sql2; } } } } if ($sql3 != "") { $sql3 .= ";"; if ($verbose) { echo $sql3 . "\n"; } if ($action) { $r = @$db->q($sql3); if (false === $r) { $errors .= t('Errors encountered performing database changes.') . $sql3 . EOL; } } } } return $errors; }
public static function changeSchema(array &$field, array $column_renames = array()) { // Update the field schema $old_schema = array_intersect_key($field, array('columns' => '', 'indexes' => '', 'foreign keys' => '')); module_load_install($field['module']); $new_schema = (array) module_invoke($field['module'], 'field_schema', $field); $new_schema += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array()); $field['data']['columns'] = $new_schema['columns']; $field['data']['indexes'] = $new_schema['indexes']; $field['data']['foreign keys'] = $new_schema['foreign keys']; $data_table = _field_sql_storage_tablename($field); $revision_table = _field_sql_storage_revision_tablename($field); // Validate that all the columns described in the existing schema actually exist. foreach (array_keys($old_schema['columns']) as $old_column) { $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column); if (!db_field_exists($data_table, $old_column_name)) { throw new Exception(); } if (!db_field_exists($revision_table, $old_column_name)) { throw new Exception(); } // Attempt to re-use any columns that have the same name. // This can be skipped by setting $column_renames['column-name'] = FALSE; if (!empty($new_schema['columns'][$old_column]) && !isset($column_renames[$old_column])) { $column_renames[$old_column] = $old_column; } } // Validate that any columns to be renamed actually exist. foreach ($column_renames as $old_column => $new_column) { if (!isset($old_schema['columns'][$old_column])) { throw new Exception("Cannot rename field {$field['field_name']} column {$old_column} because it does not exist in the old schema."); } if (!isset($new_schema['columns'][$new_column])) { throw new Exception("Cannot rename field {$field['field_name']} column {$old_column} to {$new_column} because it does not exist in the new schema."); } } // Remove all existing indexes. foreach ($old_schema['indexes'] as $index => $index_fields) { $index_name = _field_sql_storage_indexname($field['field_name'], $index); if (db_index_exists($data_table, $index_name)) { watchdog('helper', "Dropped index {$data_table}.{$index_name}"); db_drop_index($data_table, $index_name); } if (db_index_exists($revision_table, $index_name)) { watchdog('helper', "Dropped index {$revision_table}.{$index_name}"); db_drop_index($revision_table, $index_name); } } // Rename any columns. foreach ($column_renames as $old_column => $new_column) { $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column); if ($new_column === FALSE) { db_drop_field($data_table, $old_column_name); watchdog('helper', "Dropped column {$data_table}.{$old_column_name}"); db_drop_field($revision_table, $old_column_name); watchdog('helper', "Dropped column {$revision_table}.{$old_column_name}"); unset($old_schema['columns'][$old_column]); } else { $new_column_name = _field_sql_storage_columnname($field['field_name'], $new_column); db_change_field($data_table, $old_column_name, $new_column_name, $new_schema['columns'][$new_column]); watchdog('helper', "Changed column {$data_table}.{$old_column_name}<br/><pre>" . print_r($new_schema['columns'][$new_column], TRUE) . '</pre>'); db_change_field($revision_table, $old_column_name, $new_column_name, $new_schema['columns'][$new_column]); watchdog('helper', "Changed column {$revision_table}.{$old_column_name}<br/><pre>" . print_r($new_schema['columns'][$new_column], TRUE) . '</pre>'); // Remove these fields so they aren't removed or added in the code below. unset($new_schema['columns'][$new_column]); unset($old_schema['columns'][$old_column]); } } // Remove any old columns. $old_columns = array_diff_key($old_schema['columns'], $new_schema['columns']); foreach (array_keys($old_columns) as $old_column) { $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column); db_drop_field($data_table, $old_column_name); watchdog('helper', "Dropped column {$data_table}.{$old_column_name}"); db_drop_field($revision_table, $old_column_name); watchdog('helper', "Dropped column {$revision_table}.{$old_column_name}"); } // Add any new columns. $new_columns = array_diff_key($new_schema['columns'], $old_schema['columns']); foreach (array_keys($new_columns) as $new_column) { $new_column_name = _field_sql_storage_columnname($field['field_name'], $new_column); db_add_field($data_table, $new_column_name, $new_schema['columns'][$new_column]); watchdog('helper', "Added column {$data_table}.{$new_column_name}"); db_add_field($revision_table, $new_column_name, $new_schema['columns'][$new_column]); watchdog('helper', "Added column {$revision_table}.{$new_column_name}"); } // Re-add indexes. foreach ($new_schema['indexes'] as $index => $index_fields) { foreach ($index_fields as &$index_field) { if (is_array($index_field)) { $index_field[0] = _field_sql_storage_columnname($field['field_name'], $index_field[0]); } else { $index_field = _field_sql_storage_columnname($field['field_name'], $index_field); } } $index_name = _field_sql_storage_indexname($field['field_name'], $index); db_add_index($data_table, $index_name, $index_fields); watchdog('helper', "Added index {$data_table}.{$index_name}<br/><pre>" . print_r($index_fields, TRUE) . '</pre>'); db_add_index($revision_table, $index_name, $index_fields); watchdog('helper', "Added index {$revision_table}.{$index_name}<br/><pre>" . print_r($index_fields, TRUE) . '</pre>'); } }