Drupal - How to change the length of field settings?

Dylan Tack solution is the easiest, but personally I enjoy exploring the inner wards of Drupal's database to seen how things are managed down there.

So, assuming you have a text field which machine name is field_text of 10 characters you want to grow to 25:

  • data will be stored in two tables: field_data_field_text and field_revision_field_text
  • definition is stored in field_config for the storage data, and field_config_instance for each instance of this field (stuff like label).

Now let's do a little heart surgery.

  1. Alter the data tables columns definitions:

    ALTER TABLE `field_data_field_text` 
    CHANGE `field_text_value` `field_text_value` VARCHAR( 25 ) 
    CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
    
    ALTER TABLE `field_revision_field_text` 
    CHANGE `field_text_value` `field_text_value` VARCHAR( 25 ) 
    CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
    
  2. Change the definition column, this one is very tricky because it's stored in a BLOB, but that's not something that will stop you for doing this.

    • Dissect the guts of this BLOB thing:
    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    
    • This will give you something like:
    a:7:{s:12:"translatable";s:1:"1";s:12:"entity_types";a:0:{}s:8:"settings";a:2:
        {s:10:"max_length";s:2:"10";s:17:"field_permissions";a:5:
        //a lot more stuff...
    
    • This is a PHP serialized array, the interesting part is s:10:"max_length";s:2:"10";, this mean this array has a property named max_length (which name is a 10 characters string - hence the "s") which value is 10 (which is a 2 characters long string). It's pretty easy, isn't it?

    • Changing its value is as easy as replacing the s:2:"10" part by s:2:"25". Be careful: if your new value is longer in character length, you have to adapt the "s" part accordingly. For example putting 100 will be s:3:"100" as 100 length is 3 characters.

    • Let's put this new value back in the DB, don't forget to keep the whole string.

    UPDATE `field_config` 
    SET data = 'a:7:{...a:2:{s:10:"max_length";s:2:"25";...}'
    WHERE `field_name` = 'field_text'
    
    • Flush your caches.
  3. ???

  4. PROFIT!

By the way, PhpMyAdmin has some setting to allow direct modification of BLOB columns, but why go the easy way?

PS: This can also save your life when putting some PHP code in views and getting a WSOD because of an error in your code.


function mymodule_update_7100() {
  $items = array();
  _field_maxlength_fix('field_name');
  return $items;
}

function _field_maxlength_fix($field_name, $maxlength = 255) {
  _alter_field_table($field_name, $maxlength);
  $data = _get_field_data($field_name);
  $data = _fix_field_data($data, $maxlength);
  _update_field_config($data, $field_name);
}

function _alter_field_table($field_name, $maxlength) {
  db_query("ALTER TABLE field_data_".$field_name." CHANGE ".$field_name."_value ".$field_name."_value VARCHAR( ".$maxlength." ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
  db_query("ALTER TABLE field_revision_".$field_name." CHANGE ".$field_name."_value ".$field_name."_value VARCHAR( ".$maxlength." ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
}

function _get_field_data($field_name) {
  $qry = "SELECT data FROM field_config WHERE field_name = :field_name";
  $result = db_query($qry, array(':field_name' => $field_name))->fetchObject();
  return unserialize($result->data);
}

function _fix_field_data($data, $maxlength) {
  $data['settings']['max_length'] = (string)$maxlength;
  return serialize($data);
}

function _update_field_config($data, $field_name) {
  $qry = "UPDATE field_config SET data = :data WHERE field_name = :field_name";
  db_query($qry, array(':data' => $data, ':field_name' => $field_name));
}

This appears to be a limitation of the current text module. text_field_settings_form() has this comment: "@todo: If $has_data, add a validate handler that only allows max_length to increase.".

As a temporary workaround, you could comment out '#disabled' => $has_data in modules/field/modules/text/text.module, around line 77.

I couldn't find an existing issue for this specific case, but you might mention it on #372330.