1

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.

1

1 Answer 1

2

Basing on Updating Entities and Fields in Drupal 8, adding and deleting a entity field requires \Drupal::entityDefinitionUpdateManager(). (I changed the second code example to use the same field and entity name used in the first code example.)

A base field is added and removed using code similar to the following one.

$field_storage_definition = BaseFieldDefinition::create('boolean')
  ->setLabel(t('Revision translation affected'))
  ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
  ->setReadOnly(TRUE)
  ->setRevisionable(TRUE)
  ->setTranslatable(TRUE);

\Drupal::entityDefinitionUpdateManager()
  ->installFieldStorageDefinition('revision_translation_affected', 'block_content', 'block_content', $field_storage_definition);
$update_manager = \Drupal::entityDefinitionUpdateManager();
$definition = $update_manager->getFieldStorageDefinition('revision_translation_affected', 'block_content');
$update_manager->uninstallFieldStorageDefinition($definition);

The database tables aren't directly accessed. The update manager takes care of that.

1
  • Thanks. That's where I was heading. It's probably a custom problem now, but when I run the code, I'm getting [error] Error: Call to a member function getType() on null. But when I print $definition, the object prints with keys and values. I'll update my question.
    – esod
    Jul 13, 2022 at 21:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.