A custom module added a field to the node_field_data
table. Deleting the field in a hook update like this:
function HOOK_update_N() {
Database::getConnection()->schema()->dropField('node_field_data', 'my_field');
}
deletes the field, but as soon as configuration is imported a Column not found: 1054 Unknown column
error is thrown.
[error] Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'data.my_field' in 'field list':
SELECT "revision".*, "data"."my_field" AS "my_field"
FROM
"node_field_revision" "revision"
LEFT OUTER JOIN "node_field_data" "data" ON ("revision"."nid" = "data"."nid" AND "revision"."langcode" = "data"."langcode")
WHERE ("revision"."nid" IN (:db_condition_placeholder_0)) AND ("revision"."vid" IN (:db_condition_placeholder_1))
ORDER BY "revision"."nid" ASC; Array
(
[:db_condition_placeholder_0] => 100000
[:db_condition_placeholder_1] => 200000
)
in Drupal\Core\Entity\Sql\SqlContentEntityStorage->loadFromSharedTables() (line 579 of /var/www/html/docroot/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).
Here’s the same query, only more readable.
SELECT revision.*, data.my_field AS my_field
FROM node_field_revision revision
LEFT OUTER JOIN node_field_data data ON (revision.nid = data.nid AND revision.langcode = data.langcode)
WHERE (revision.nid IN (100000)) AND (revision.vid IN (200000))
ORDER BY revision.nid;
So the config import is triggering some cleanup and dropField()
on the database is not the way to go.
I seem to recall some other modules, maybe lingotek or workbench_moderation, adding a field to the node_field_data
table at one point. I wonder how they got their field out of the table if that was so?
The core content_translation module adds field to the node_field_data
table.
Yes, thanks, the database tables aren't directly accessed. I'm also uninstalling the module, so I'm using hook_uninstall()
like this:
/**
* Implements hook_uninstall().
*/
function my_module_uninstall() {
$update_manager = \Drupal::entityDefinitionUpdateManager();
$definition = $update_manager->getFieldStorageDefinition('my_field', 'node');
$update_manager->uninstallFieldStorageDefinition($definition);
}
But when I run drush -y pmu my_module
, I'm getting a
[error] TypeError: Argument 1 passed to Drupal\Core\Entity\EntityDefinitionUpdateManager::uninstallFieldStorageDefinition() must implement interface Drupal\Core\Field\FieldStorageDefinitionInterface, null given,
error.
Update: The error was because there was content in the field. We decided to do this in an update hook, not a hook_uninstall
hook.
Here's that version of the code:
function my_module_update_N() {
if (!\Drupal::database()->schema()->fieldExists('node_field_data', 'my_field')) {
return;
}
// First, delete the content from the field.
\Drupal::database()->query("UPDATE {node_field_data} SET my_field = NULL WHERE my_field IS NOT NULL");
// Use the update manager to uninstall the field.
$update_manager = \Drupal::entityDefinitionUpdateManager();
$definition = $update_manager->getFieldStorageDefinition('my_field', 'node');
$update_manager->uninstallFieldStorageDefinition($definition);
$update_manager->updateEntityType($update_manager->getEntityType('node'));
// Required because other hook updates and/or post-updates may run immediately after.
drupal_flush_all_caches();
}
I add updateEntityType()
and drupal_flush_all_caches()
because of the next error. The next error was when the build got to the config:import step, it was throwing this error:
In ExceptionHandler.php line 53:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'my_field' in 'where clause': SELECT 1 AS "expression"
FROM
"node_field_data" "t"
WHERE "my_field" IS NOT NULL
LIMIT 1 OFFSET 0; Array
(
)
In StatementWrapper.php line 145:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'my_field' in 'where clause'
So then we tried the module installer service:
function my_module_update_N() {
// Use module handler because it removes the my_module field from the node_field_data table.
if (\Drupal::moduleHandler()->moduleExists('my_module')) {
\Drupal::service('module_installer')->uninstall(['my_module']);
}
}
Per the comment in the hook update, not only did the module handler delete the field in node_field_data, but it "alerted" other processes like config:import that the field was gone. The config is imported successfully, the build completes successfully, and the problem has been solved.