(description follows)

CommentFileSizeAuthor
#111 oh_no_reopened_again.patch2.31 KBDavid_Rothstein
#105 thats_what_you_get_for_skipping_process.patch812 byteschx
#104 thats_what_you_get_for_skipping_process.patch496 byteschx
#96 interdiff_88_95.patch1.86 KBchx
#95 drupal.format-exists-update.95.patch10.53 KBsun
#90 drupal.format-exists-update.90.patch10.58 KBsun
#89 934050-88_format_followup.patch9.79 KBalex_b
#83 934050-83_format_followup.patch9.48 KBalex_b
#82 format-934050-followup-81.patch8.72 KBalex_b
#80 format-934050-followup-80.patch8.1 KBalex_b
#77 format-934050-followup-77.patch6.52 KBDavid_Rothstein
#76 format-934050-followup-75.patch3.51 KBDavid_Rothstein
#75 934050-75_tests.patch3.1 KBalex_b
#67 drupal.format-update.67.patch2.65 KBsun
#66 drupal.format-update.66.patch2.53 KBsun
#64 text_update.gif7.24 KByettyn
#58 annoyed.patch782 bytescatch
#50 934050-49_filter_format.patch25.66 KBalex_b
#44 drupal.filter-format.44.patch38.89 KBsun
#43 drupal.filter-format.43.patch38.11 KBsun
#42 drupal.filter-format.41.patch38.16 KBsun
#39 drupal.filter-format.39.patch37.44 KBsun
#38 drupal.filter-format.38.patch34.26 KBsun
#37 drupal.filter-format.37.patch35.28 KBsun
#36 drupal.filter-format.36.patch34.04 KBsun
#35 drupal.filter-format.35.patch35.05 KBsun
#30 drupal.filter-format.30.patch32.76 KBsun
#26 drupal.filter-format.26.patch26.36 KBsun
#25 drupal.filter-format.25.patch26.18 KBsun
#24 drupal.filter-format.24.patch24.95 KBsun
#23 drupal.filter-format.23.patch23.36 KBsun
#18 drupal.filter-format.18.patch23.35 KBsun
#12 drupal.filter-format.12.patch21.71 KBsun
#2 drupal.format-name.2.patch20.82 KBsun
drupal.format-name.0.patch13.88 KBsun
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Status: Needs review » Needs work

The last submitted patch, drupal.format-name.0.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
FileSize
20.82 KB
sun’s picture

Problem

  • Text formats are not exportable into code, therefore don't really work for building distros.
  • Even if text formats had an additional machine name, there would not be a guarantee that format ID 2 is actually format "two". If some node, view, or anything references format 2 for a content, the content may be rendered in the wrong text format.
  • Any attempt to export text formats as is, is therefore a major security risk.

Goal

  • Introduce proper machine names for text formats, with the smallest possible API change.

Details

  • Instead of trying to additionally introduce a machine name for text formats and trying to map that to format IDs...
  • ...we change all format columns from int to varchar.
  • It makes no difference for SQL/NoSQL whether formats are stored as integers or strings. We rarely (never?) filter or sort on that column anyway, so the data is almost always used in PHP only.
  • The administrative text format UI gets a new machine name form element to enter the name (still format) for new text formats. Existing machine names cannot be changed (since format IDs could not be changed either).
  • Although it is slightly weird to have machine names of "1", "2", all existing format column values are simply converted from an integer to a string. Of course, new D7 sites get proper machine names in the form of plain_text, filtered_html, and full_html. The straightforward and dead simple conversion from integers only happens for sites upgrading from D6.
  • Half of this pretty small patch are changes for tests that currently reference hard-coded format IDs. The other half is changing schema definitions accordingly, and performs the required changes to Filter module. The size of this patch and the actual changes prove that this is the most simple solution.
  • This is the least invasive way to support proper machine names for text formats. It's so stupidly simple that it can only work. (And it works.)

API changes

  • All format columns that currently reference a format ID are converted to varchar.
  • The $format object passed to filter_format_save() requires $format->format to be defined.

Required patches

Required follow-up issues

Status: Needs review » Needs work

The last submitted patch, drupal.format-name.2.patch, failed testing.

Damien Tournoud’s picture

Just to state the obvious: you need an upgrade path for (text) fields.

And it would have been *way* easier to do that *before* the beta.

mfer’s picture

sub

sun’s picture

Status: Needs work » Needs review
Issue tags: +Needs committer feedback

Actually, the last patch failed due to a testbot hiccup. It's green now.

Of course, an upgrade path for text fields is still missing. I have no idea how to do that, but I guess I will find out. ;) However, before continuing with this patch, I'll wait for some sign of the core maintainers.

Crell’s picture

Status: Needs review » Needs work

Re #5: Yes. See #933846: Better distro support for all the messy background. :-)

I see two possibilities for the upgrade path:

Ints are still valid strings. There's, programmatically, nothing about "1" that makes it invalid as a string identifier. We could just leave it. :-) An advantage of this approach overall is that, because ints are valid strings, the API breakage is kept to an absolute minimum.

As an extension of that, simply add a prefix. format 1 becomes "format_1", format 2 becomes "format_2", etc. I believe coder upgrade module did that for block deltas, which also switched from mostly ints to must-be-string in D7.

+++ modules/block/block.install	7 Oct 2010 02:21:14 -0000
@@ -155,8 +155,8 @@ function block_schema() {
-        'type' => 'int',
-        'unsigned' => TRUE,
+        'type' => 'varchar',
+        'length' => 64,

+++ modules/filter/filter.admin.inc	7 Oct 2010 02:30:54 -0000
@@ -122,6 +125,16 @@ function filter_admin_format_form($form,
+    '#type' => 'textfield', // @todo http://drupal.org/node/902644

While I cannot think of a use case off hand for a machine name longer than 64 characters, we've been bitten by too-short varchar fields in the past many many times. Especially if we end up with dynamically created machine names (which will happen sooner or later; it always does). We probably want to make this bigger and save ourselves the headache later.

+++ modules/field/modules/text/text.test	7 Oct 2010 02:26:21 -0000
@@ -386,8 +389,15 @@ class TextTranslationTestCase extends Dr
-    $this->format = 3;
-    $this->admin = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages', 'bypass node access', "use text format $this->format"));
+    $full_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchObject();
+    $this->format = $full_html_format->format;

If the idea is to have a machine name, why is this being queried by human name?

+++ modules/filter/filter.module	7 Oct 2010 02:21:14 -0000
@@ -192,7 +192,8 @@ function filter_format_save(&$format) {
   // Add a new text format.
-  if (empty($format->format)) {
+  $exists = db_query_range('SELECT 1 FROM {filter_format} WHERE format = :format', 0, 1, array(':format' => $format->format))->fetchField();
+  if (!$exists) {
     $return = drupal_write_record('filter_format', $format);
   }

This seems like a potentially good case for a merge query instead.

Powered by Dreditor.

eaton’s picture

Ints are still valid strings. There's, programmatically, nothing about "1" that makes it invalid as a string identifier. We could just leave it. :-) An advantage of this approach overall is that, because ints are valid strings, the API breakage is kept to an absolute minimum.

In the D6 world, this is what we're looking at in moving Workflow module from serial ids to machine names for its workflows. I'm partial to the "Just turn the ID into a string" approach because it utterly eliminates any danger of stray ids being scattered around and missed by the upgrade path.

As an extension of that, simply add a prefix. format 1 becomes "format_1", format 2 becomes "format_2", etc. I believe coder upgrade module did that for block deltas, which also switched from mostly ints to must-be-string in D7.

This is purely aesthetic, though, isn't it? There's nothing (in theory) to keep us from just using the numeric ones. That's what was also done for node build modes in previous versions of Drupal -- while it was less than ideal, we demonstrated that contrib can build on that effectively.

yhahn’s picture

I've read and applied the patch in #2. It works as expected and makes working with filter formats in code more readable (see adjustments to tests and use of API to create filter formats). This is a much cleaner approach to introducing machine names into core than adding an additional column - it means contrib can continue to use the same ->format property and have a minimal upgrade path that involves at most a small schema change (like the changes in patch to taxonomy.install) or no changes at all if format references are stored flexibly in a serialized field or a variable.

Other than Crell's notes in #8, this patch will need an upgrade path which I am happy to help with and test.

Crell’s picture

Eaton: Actually, if anything I think the node build modes in D6 is a great example of why we should convert to strings. :-) To this day I am still mystified by what I can do with D6 build modes and do not comprehend why I sometimes get different lists.

sun’s picture

Status: Needs work » Needs review
FileSize
21.71 KB

Thanks for the initial reviews and testing.

I agree that we should not do any special string manipulation and simply convert existing IDs to strings. Like yhahn mentioned, this not only simplifies the upgrade path for all modules, but also allows serialized data to be stored as is. For the Filter API, it really makes no difference whether $format->format is "1" or "format_1". Since it makes no difference, there's no need to complicate this update path.

@Crell: I already considered to use db_merge(), but we're facing the following code situation:

  $exists = db_query_range('SELECT 1 FROM {filter_format} WHERE format = :format', 0, 1, array(':format' => $format->format))->fetchField();
  if (!$exists) {
    $return = drupal_write_record('filter_format', $format);
  }
  else {
    $return = drupal_write_record('filter_format', $format, 'format');
  }

1) $format is an object, not an array, not sure whether db_merge() is smart enough to handle objects?

2) If db_merge() cannot handle objects, then we'd have to cast to an array into a temporary variable and pass that into ->fields().

3) We'd have to manually assign all potentially undefined properties for $format before or after saving. Right now, d_w_r() takes over that part.

Ultimately, I doubt that db_merge() would make this any simpler?

Also, non-obvious @todos for this patch:

- I've removed the unique index on {filter_format}.name. filter.admin.inc still contains form validation logic for that uniqueness. Also, the filter_update_N() does not remove the index.

- The 'filter_fallback_format' variable might need to be updated accordingly. For extra safety, I've changed the comparison in filter_permission_name() to a type-agnostic comparison, so $format->format !== filter_fallback_format() will fail, if one of both is not a string. Need to think about this some more, it might be possible that we can also revert it.

Crell’s picture

No, db_merge() doesn't handle objects. It's a simple cast, though. And if a field isn't defined, the DB should fill in the default anyway, shouldn't it? d_w_r() just pulls its defaults from the schema anyway. Even then, are we actually going to get partially-filled $format objects in practice (that don't count as broken code to begin with)?

I admit I'm somewhat biased since I consider d_w_r() to be a blight upon the earth to be exterminated with religious zeal; its only reason to exist is that db_merge() didn't exist yet as of Drupal 6 and we haven't fully gotten around to expunging its evil from the world.

Possibly unrelated here, but I also note that the filter table has a field (that's being modified here) that is marked as being a foreign key in the description but doesn't have its FK-ness defined in the schema API. We should fix that.

webchick’s picture

"- I've removed the unique index on {filter_format}.name. filter.admin.inc still contains form validation logic for that uniqueness. Also, the filter_update_N() does not remove the index."

That doesn't make sense to me. There are other ways to create formats than through the UI. What problem does removing this index actually solve?

sun’s picture

@webchick: The human-readable name of a format is unimportant with this patch. Until now, we tried ;) to enforce some kind of uniqueness for text format labels, but those can be changed at any time, so it's like renaming a node type's label. Completely unnecessary if there is a unique machine name.

sun’s picture

@Crell: I understand. However, the difference is that d_w_r() populates $format with all default properties and values that were not necessarily defined. Since hooks are invoked afterwards, we absolutely have to make sure that the $format object is fully populated. Therefore, if we'd go with db_merge(), then we'd have to resemble the schema's default values before or after the db_merge(), test each property individually, and conditionally set it. Hm. AFAICS, the only property that's not covered yet, is $format->weight... so lemme re-roll ;)

Crell’s picture

db_merge() followed by a select would do it, wouldn't it? :-) It's the same number of queries.

sun’s picture

Changed into db_merge(), and resolved all non-obvious @todos from #12.

moshe weitzman’s picture

I agree with webchick and don't grok sun's response. Format should be a sole primary key in its table. Right now, it looks like (format, name) is the primary key. Duplicate machine names should be enforced at DB level in addition to FAPI.

moshe weitzman’s picture

If we *also* want a unique index on name, thats fine.

Status: Needs review » Needs work

The last submitted patch, drupal.filter-format.18.patch, failed testing.

Dries’s picture

Overall, I like the approach taken in this patch. It's not as bad of an API change as I expected it to be so I think we should seriously consider this for Drupal 7. Let's continue to flush out the remaining glitches.

sun’s picture

Status: Needs work » Needs review
FileSize
23.36 KB
+++ modules/filter/filter.install	8 Oct 2010 23:45:14 -0000
@@ -97,9 +98,6 @@ function filter_schema() {
     'primary key' => array('format'),
-    'unique keys' => array(
-      'name' => array('name'),
-    ),

Sorry, can someone clarify the confusion, please? {filter_format}'s primary key is only 'format', nothing else. We previously had an additional unique key for 'name' -- but only because we had no other way to ensure that a certain format only exists once. Since 'format' becomes the machine name now, it already ensures uniqueness, so there is little point in additionally requiring that 'name' must be unique. Especially, since we just recently added functionality to disable text formats (but not delete them), this is the only way to re-add a text format that uses the same name as a previously disabled one.

I hope that clarifies the situation.

Powered by Dreditor.

sun’s picture

To fill in the obvious gaps.

I'm not really sure whether anyone ever thought about doing Field API updates. My head just imploded multiple times...

sun’s picture

Really, my brain exploded. See code comments in text_update_7000().

sun’s picture

sun’s picture

+++ modules/field/modules/text/text.install	9 Oct 2010 02:41:38 -0000
@@ -66,3 +66,53 @@ function text_field_schema($field) {
+/**
+ * Change text field 'format' columns into varchar.
+ */
+function text_update_7000() {
+  // @todo Don't invoke hooks in updates.
+  $all_fields = field_info_fields();
+  foreach ($all_fields as $field_name => $field) {
+    if (strpos($field['type'], 'text_') === 0) {
+      // Only field_sql_storage happens to be supported by Drupal core. It is
+      // entirely unclear how schema/module updates for other field storage
+      // engines are supposed to work. No module (and also not Text module)
+      // can take care for all possibly existing storage engines, so either
+      // there has to be an schema and/or data abstraction layer in Field API
+      // for running updates, or we blatantly failed to properly design field
+      // storage engines.
+      if ($field['storage']['type'] == 'field_sql_storage') {
+        // @see _field_sql_storage_schema()
+        $real_name = _field_sql_storage_columnname($field['field_name'], 'format');
+        // @see field_sql_storage_field_attach_rename_bundle()
+        $table_name = _field_sql_storage_tablename($field);
+        $revision_name = _field_sql_storage_revision_tablename($field);
+        db_change_field($table_name, $real_name, $real_name, array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => FALSE,
+        ));
+        db_change_field($revision_name, $real_name, $real_name, array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => FALSE,
+        ));
+      }
+    }
+  }
+}

To make any sense of field storage engines in D7, everything below the lengthy comment must live in a Field API function.

But hey, now comes the tricky part: We are not allowed to invoke module functions or hooks in module updates.

This means that field_sql_storage module has to be duplicated into field_sql_storage.install.

And the same needs to happen for any other field storage engine in contrib.

Lastly, field.install needs to contain module update API functions, because the API functions cannot live in the module, since we are not supposed to invoke module functions from updates.

Powered by Dreditor.

chx’s picture

Version: 7.x-dev » 8.x-dev
Status: Needs review » Needs work

Although I have stopped doing D7 work because I was called a problem and until I get an apology for that I am not going to do anything, I had enough of sun's allegations of how field storage engines are badly designed. Dude. We did not design it in a basement closed away from the world and then locked it down for good. Quite the opposite. Even when we were sprinting we were giving reports often. And after that you had two years to contribute and speak up if you had a problem. We made it crystal clear that the divisor between fields and instances is that fields get the things that are hard to update. Like, you know, the schema.

Now, the main argument against keeping the rules as they stand for everyone is that we do not have an export-import tool that can handle variables? Create a text format, save the id into a variable and then use that variable to create, say, a view. As what you want is a distro, this is perfectly doable as you know your own variables. This can be done without doing a schema change past beta.

chx’s picture

sun’s picture

Version: 8.x-dev » 7.x-dev
Status: Needs work » Needs review
FileSize
32.76 KB

Attached patch resolves the problem. Constructive feedback welcome.

Status: Needs review » Needs work

The last submitted patch, drupal.filter-format.30.patch, failed testing.

chx’s picture

+ foreach (module_implements('field_update_forbid') as $module) does not belong in an update function.

sun’s picture

The current field_update_field() does invoke hook_field_update_forbid() to allow field storage engines to veto a field update. Sure, we can remove that from the update helper, but that would make the API inconsistent with the regular Field CRUD API. In the end, field updates always have to invoke modules, because field storage engines simply are modules, so there's little point in restricting invocation of module hooks for field updates.

That said, I'm not entirely sure why that forbid-hook exists at all. If a particular field storage engine cannot or does not want to execute a field update, it can simply ignore it, or throw a FieldException in the engine-specific update hook. In other words: I cannot think of a scenario where any other module would want to prevent a field update from happening. Only the field storage engine is able to decide that on its own. If a developer disagrees with a field storage engine's behavior, then that developer can fork the field storage engine to behave like he/she thinks it's right and use that storage engine instead.

David_Rothstein’s picture

The human-readable name of a format is unimportant with this patch. Until now, we tried ;) to enforce some kind of uniqueness for text format labels, but those can be changed at any time, so it's like renaming a node type's label. Completely unnecessary if there is a unique machine name.

I once thought so too...

But then was educated otherwise: http://drupal.org/node/11218#comment-1986086

Those proposed changes are a separate issue and should not be part of this patch.

sun’s picture

Status: Needs work » Needs review
FileSize
35.05 KB
sun’s picture

Reverted the removal of enforced {filter_format}.name uniqueness.

sun’s picture

Simplified and clarified text_update_7000() by remixing some lines.

sun’s picture

oopsie -- in-patch edits are a bad idea if you happen to forget to also change the actual code... Reverted those {filter_format}.name uniqueness changes once again ;)

sun’s picture

+++ modules/field/field.install	9 Oct 2010 23:14:57 -0000
@@ -334,6 +344,66 @@ function _update_7000_field_read_fields(
+  if ($field['type'] != $prior_field['type']) {
+    throw new FieldException("Cannot change an existing field's type.");
+  }
+  if ($field['entity_types'] != $prior_field['entity_types']) {
+    throw new FieldException("Cannot change an existing field's entity_types property.");
+  }

Thinking through all possible scenarios that field type modules can face, we need to remove those lines entirely. It might make sense for Field UI to prevent such updates, but field type modules have to be able to maintain all and any kind of their data, regardless of whether a module is renamed or it's just a simple field schema change.

+++ modules/field/field.install	9 Oct 2010 23:14:57 -0000
@@ -334,6 +344,66 @@ function _update_7000_field_read_fields(
+  // See if any module forbids the update by throwing an exception.
+  foreach (module_implements('field_update_forbid') as $module) {
+    $function = $module . '_field_update_forbid';
+    $function($field, $prior_field, $has_data);
+  }

This is still contained. I'd like to hear some more opinions on this. If there are no real reasons for this hook to exist, we might as well remove it entirely (also from field_update_field()).

See #33 for why I think this is hook is pointless.

+++ modules/field/field.install	9 Oct 2010 23:14:57 -0000
@@ -334,6 +344,66 @@ function _update_7000_field_read_fields(
+  $data = $field;
+  unset($data['columns'], $data['field_name'], $data['type'], $data['locked'], $data['module'], $data['cardinality'], $data['active'], $data['deleted']);
+  // Additionally, do not save the 'bundles' property populated by
+  // field_info_field().
+  unset($data['bundles']);

Separate issue: This code is repeated many times throughout Field API. However, the current serialized 'data' column still contains stuff it should not contain (such as field schema data), so we really need a solid helper function for this operation.

Again, separate issue.

+++ modules/field/field.install	9 Oct 2010 23:14:57 -0000
@@ -334,6 +344,66 @@ function _update_7000_field_read_fields(
+  // Store the field and create the id.
+  $primary_key = array('id');
+  drupal_write_record('field_config', $field, $primary_key);

Changed this into a db_update() in attached patch. Update functions must not rely on Schema API.

Powered by Dreditor.

sun’s picture

Tests are failing, because field_update_field() currently happens to rely on the coincidence that the serialized {field_config}.data column mistakenly (?) also contains field schema information. The current code of field_update_field() entirely relies on hook_field_schema() and I fail to see how that code can remotely work under normal circumstances.

Right now, field_update_field() tries to update a field by automatically generating the previous schema information for it, which naturally fails, because the field type schema is always up to date. Only the current code in HEAD that makes field schema information appear in {field_config}.data allows that code to work. This looks completely bogus to me, but then again, I'm not sure whether it was purposively designed that way (lacking alternatives).

Status: Needs review » Needs work

The last submitted patch, drupal.filter-format.39.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
FileSize
38.16 KB

But yeah. That critical bug is irrelevant for this issue, so I went ahead and commented out the fix; added a @todo instead.

sun’s picture

Fixed update of field_config storage columns.

sun’s picture

Apparently, field storage engine settings in $field['storage']['settings'] were also (mistakenly?) contained in the serialized field_config.data column.

Status: Needs review » Needs work

The last submitted patch, drupal.filter-format.44.patch, failed testing.

chx’s picture

Now, this became a kitten killer monstrosity. You are changing which keys are unset field_update_field, adding a $conditions mechanism for field_update_field, creating a problematic and controversial _update_7000_field_update_field utility, changing field_sql_storage_field_update_forbid / field_sql_storage_field_storage_update_field, the accompanying test. http://www.webchick.net/please-stop-eating-baby-kittens

No. File different issues. This is completely and absolutely unreviewable. I would be glad to work with you to get field API problems fixed in a speedy manner but not in one issue which, in itself, is not yet approved by Dries to be Drupal 7 anyways.

sun’s picture

alex_b’s picture

Assigned: sun » alex_b

#44 is broken out to #937554: Field storage config entities 'indexes' key.

chx suggested to write a field_sql_storage-engine-only update hook for changing the field schema for format. Let me give this a shot.

alex_b’s picture

Assigned: alex_b » Unassigned
Status: Needs work » Needs review

This is patch #44 with the following modifications:

- Implement text_update_7000() for SQL storage engine only (this removes the entire _update_7000_field_update_field($prior_field, $field) portion of #44).
- Use form element #type 'machine_name' after #902644 went in.

alex_b’s picture

yched’s picture

Note that we'll still need update-friendly versions of field_update_field() / field_update_instance(). There will be housekeeping of stored $field and $instance definitions. Those could possibly be just the 'array-massaging-into-SQL-friendly-structure' part of their 'official API' counterparts - that is, once those very parts are sorted out in #937554: Field storage config entities 'indexes' key.

Not necessary for this patch if it can live without, though.

Crell’s picture

#50 looks good to me on visual inspection. I defer to the Field API experts on #51. Nice use of machine_name, too.

sun’s picture

Status: Needs review » Reviewed & tested by the community

Right -- so we're basically back to the originally posted patch in #26, merely with a marginal difference in text_update_7000().

+++ modules/field/modules/text/text.install	15 Oct 2010 19:50:08 -0000
@@ -66,3 +66,35 @@ function text_field_schema($field) {
+    $table = _field_sql_storage_tablename($prior_field);
+    $revision_table = _field_sql_storage_revision_tablename($prior_field);
+    $field_name = _field_sql_storage_columnname($field['field_name'], 'format');

These functions live in field_sql_storage.module. They merely concatenate the passed in values and do not invoke hooks. So it should not be a problem to invoke them.

Background: Over in #922996: Upgrade path is broken since update.php does not enforce empty module list, there's an ongoing discussion about emptying/resetting the module list and hook implementation cache prior to executing a module update (to prevent invocation of hooks). It doesn't look like it affects those function invocations though.

Powered by Dreditor.

q0rban’s picture

Subscribe

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Decided to commit this patch to help us improve support for distributions.

Thanks for working on this, for trusting my judgment and respecting the decision.

Let's continue to make progress, please.

rfay’s picture

Issue tags: -Needs committer feedback

Wow, amazing.

Created issue #946876: Filter format IDs are now strings! Use descriptive IDs in Filter Example for examples project to utilize this. It seems more than half of D6 code that provides blocks uses an int for the delta, even though it became string all that long ago. We really don't want that to happen with filter IDs so we should promote the new use aggressively.

I think this should probably be announced too, even though it doesn't break anything.

chx’s picture

Title: Change format into string » [SECHOLE] Change format into string
Category: task » bug
Priority: Normal » Critical
Status: Fixed » Active

OK, tell me that after linking http://drupal.org/node/11218#comment-1986086 how did we commit dropping human name unique index?

Each text format human-readable name should be unique, as it's the resource that users have to identify them among others text formats. Having several text formats with the same human-readable names is a potential security risk, will be easy for users and admins to forget what is each text format intended for, what and configuration should be applied to each. On the final user side, how will them know which text format to use if they have exactly the same name.

catch’s picture

Status: Active » Needs review
FileSize
782 bytes

Not only this but the schema definition wasn't updated to remove the unique key, it was only dropped in the update.

This is precisely the kind of fallout that allowing schema and changes past beta creates, as the original issue spawns more and more followups.

Since it has only been a few hours since this was committed, let's hope no-one ran the update yet and just remove that hunk. If people care about the few hours window, they can open a head2head issue.

If people were feeling helpful, they could open an issue for mongodb_field_storage module for this too - mongo doesn't need a schema change, but it's type strict, so it's likely all the int values in mongo storage will need converting from text to string types in place, otherwise queries on the wrong type will fail.

chx’s picture

Status: Needs review » Reviewed & tested by the community

That sounds a plan. Those who want that unique dropped can open another issue because it does not belong to this one in the first place!

catch’s picture

In #35 the hook_schema() change and the update hook were both in, in #36 the schema change was reverted.

So it looks like sun forgot to revert the update hunk, and then everyone was so excited about distributions that they didn't notice in the 11 days between the patch being posted and committed. Which makes this no less annoying but I don't think there's anything else needs to be done apart from removing that hunk and closing this issue again as quickly as possible.

webchick’s picture

Title: [SECHOLE] Change format into string » Change format into string
Status: Reviewed & tested by the community » Fixed

Committed #58 to HEAD.

David_Rothstein’s picture

Category: bug » task
Priority: Critical » Normal
Status: Fixed » Needs work
Issue tags: +Needs documentation

Needs to be documented in the module upgrade guide, since it affects any module that stores text format data.

David_Rothstein’s picture

Title: Change format into string » Change format into string (upgrade path broken)
Category: task » bug
Priority: Normal » Critical

Looking at the patch, this also seems like it broke the upgrade path for taxonomy.module - sites upgrading from D6 (or D7 beta 1) will still wind up having {taxonomy_term_data}.format be an integer, won't they?

yettyn’s picture

FileSize
7.24 KB

Sorry to spoil the party but "Commit #438848 by Dries at 03:15" including changes to "Drupal core: /modules/field/modules/text/text.install 1.3" fails on running update.php with a "DatabaseSchemaObjectDoesNotExistException", see attached screen shot.

dev version before this one was from Oct-18

It's above my head but though to let you know it breaks, possibly because I missed a dev version in between?

yched’s picture

[edit : crosspost with #64]

The D7->D7 upgrade is also broken.
text_update_7000() raises an exception in DatabaseSchema_mysql::changeField() :
"Cannot change the definition of field field_data_.comment_body_format: field doesn't exist."

That's most probably because of :

foreach ($fields as $field_name => $field) {
  $table = _field_sql_storage_tablename($prior_field);
  $revision_table = _field_sql_storage_revision_tablename($prior_field);

$prior_field is undefined - should be $field.

AAMOF, I'd recommend hardcoding table names in the update func. If for some reason field_sql_storage changes its table naming convention in the future, the _field_sql_storage_tablename() function will return a table name that does not match the state of the db at the time the text update is run. We had similar cases in CCK, and had to insert schema version checks inside the tablename() functions back then.

sun’s picture

Status: Needs work » Needs review
FileSize
2.53 KB
sun’s picture

yched’s picture

The fix for text_update_7000() is good - tested, works fine.

I'll let David feedback on the taxo update fix.

yettyn’s picture

#67 works for me, thanks.

webchick’s picture

Priority: Critical » Normal
Status: Needs review » Needs work

Committed #67 to HEAD. Hopefully that makes testbot a bit happier. And this is why we shouldn't make schema changes during beta. :D

Reverting back to "needs work" for documentation.

catch’s picture

Issue tags: +Needs tests

Those upgrade path changes should have been caught by tests. Or was the test bot actually down?

alex_b’s picture

Assigned: Unassigned » alex_b

Great to see this committed. Sorry for the fallout.

Just talked to sun, I will supply tests and upgrade documentation shortly.

David_Rothstein’s picture

I'll let David feedback on the taxo update fix.

It looks fine to me, and I tested that it works also.

At least for this one, I think it would be hard to write an upgrade test that catches it. There is no error on upgrade (just a different schema) - you wouldn't see anything actually explode on your site until you (a) created a new text format, and then (b) assigned it to a taxonomy term description.

The text.module update issue, though, yeah - that could probably have a test.

alex_b’s picture

Issue tags: -Needs documentation

Documentation requested in #62 is up: http://drupal.org/node/224333#text_format_string

alex_b’s picture

Assigned: alex_b » Unassigned
Status: Needs work » Needs review
FileSize
3.1 KB

Adds upgrade tests for

- filter_format.format
- user.signature_format
- block_custom.format

My questions:

- Did I add the test in the right place (simpletest/tests/upgrade/upgrade.filter.test)?
- What other upgrades should be tested?

David_Rothstein’s picture

Title: Change format into string (upgrade path broken) » Change format into string (security hole)
Priority: Normal » Critical
FileSize
3.51 KB

I spent some more time thinking about the committed patch, and there are a couple more issues here, including another security problem.

  1. There is some out-of-date documentation, particularly for filter_format_save(). Fixed in the attached patch.
  2. When creating a new text format, the machine-readable name is validated using filter_format_load() which only returns enabled formats, not "disabled" (a.k.a. deleted-but-still-hanging-around-the-database) ones. That is a bug, and although somewhat of an edge case, it leads to a security issue as follows:

    Suppose you have a text format that is used on your site, and there is content stored with it. Then you disable the format. Now you go create a new text format and decide to give it the same machine-readable name as the old one had. Boom. Instead of creating a new format, what happens is that the old disabled format is "turned on" again, and is given all the properties+filters that the old one had. So all your content starts displaying again, but in a completely different format. That is a security hole.

    The attached patch fixes that by adding a new filter_format_exists() function, although:

    • It could certainly use a test.
    • A better fix might be to change the behavior of filter_format_load()... but that would just be adding API changes on top of API changes at this point.
David_Rothstein’s picture

Oops, crosspost.

Here are the two patches merged together. Could still use a test for the security issue I mentioned above, though.

David_Rothstein’s picture

On a brighter note, here is a nice cleanup issue that the original committed patch here allows :)

#947844: Clean up filter-related tests that load text formats by their human-readable name

alex_b’s picture

Assigned: Unassigned » alex_b

Adding a test for #76

alex_b’s picture

Assigned: alex_b » Unassigned
FileSize
8.1 KB

- Added a test attempting to create a format of an existing machine name.

I see one existing assertion of the filter tests failing on my local *vanilla* D7 installation ('Filter removed invalid tag.'), let's see what test bot says.

Status: Needs review » Needs work

The last submitted patch, format-934050-followup-80.patch, failed testing.

alex_b’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
8.72 KB

- Fixed checking for existing filter format _names_ (this was broken due to a check for the presence of $form_state['values']['format'] - which now is always present).
- Added a test verifying that filter formats of the same name can't be created.

alex_b’s picture

Per discussion w/ chx on IRC, I've improved the following comments:

- Compare functionality between filter_format_load() and filter_format_exists() in filter_format_exists() comment.
- Comment on format_set_value() in filter_admin_format_form_validate().
- Improve comments on assertions verifying that it isn't possible to create duplicate machine names / human readable names even if text formats in question are disabled.

chx’s picture

Status: Needs review » Reviewed & tested by the community

Looks good!

webchick’s picture

Issue tags: +beta blocker

I'd love to see a final +1 here from sun or David Rothstein, but looks good here. Thanks for the quick rally.

Tagging as beta blocker because it'd be good to get this new feature completely polished off beforehand.

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs review

Looks mostly good, and nice catch on the isset() thing in filter_admin_format_form_validate()... It seems there is a similar isset() check in filter_admin_format_form_submit() that could also be removed? But it doesn't have to be done here.

The first new filter module test looks good to me, but I don't understand the second one:

+    // Attempt to create a format of the same human readable name as the
+    // disabled format but with a different machine name.
+    $edit = array(
+      'format' => 'new_format',
+      'name' => $format->name,
+    );
+    $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
+    $this->assertText('Text format names must be unique. A format named ' . check_plain($format->name) . ' already exists.');

As far as I know, that behavior is a bug to be fixed, not something we should be verifying in a test :) ... (See the followup discussion in #914458: Remove the format delete reassignment "feature" - which I will move to its own issue after writing this.) If the format has been disabled, it is completely gone from the user interface, so we don't have any reason to prevent people from trying to create a new one with the same name.

chx’s picture

David, so how should we proceed? Remove that test?

David_Rothstein’s picture

Yeah, I would say remove it. Either that or modify it, so that the test tries to reuse the human-readable name of an enabled format instead. (Since that restriction is something we definitely do want to enforce.)

alex_b’s picture

- Removes the stray isset() that David mentions in #86

Re: #86 test for unique human readable names: Let's keep this test in, as it verifies existing functionality - even though the functionality itself may be questionable. When #914458 lands, this test will need modification - great way to ensure test coverage =)

sun’s picture

+++ modules/filter/filter.module
@@ -288,6 +293,23 @@ function filter_format_disable($format) {
+function filter_format_exists($format_id) {
+  return (bool) db_query_range('SELECT 1 FROM {filter_format} WHERE format = :format', 0, 1, array(':format' => $format_id))->fetchField();
+}

We need to take #903730: Missing drupal_alter() for text formats and filters into account. I tried to think of ways to encapsulate a $include_disabled logic into filter_formats(), but that would be too complex. Thus, attached patch merely changes this function body in preparation for the drupal_alter() patch.

Powered by Dreditor.

Status: Needs review » Needs work
Issue tags: -beta blocker

The last submitted patch, drupal.format-exists-update.90.patch, failed testing.

effulgentsia’s picture

Status: Needs work » Needs review
Issue tags: +beta blocker

#90: drupal.format-exists-update.90.patch queued for re-testing.

#90's bot hiccup has been happening a lot lately :(

David_Rothstein’s picture

+function filter_format_exists($format_id) {
+  $formats = db_select('filter_format', 'ff')
+    ->fields('ff')
+    ->condition('format', $format_id)
+    ->execute()
+    ->fetchAllAssoc('format');
+
+  return isset($formats[$format_id]);
+}

I don't understand this change. Why do we want to load the entire contents of that row just to check if the row exists? If that behavior is needed for #903730: Missing drupal_alter() for text formats and filters, then in my opinion it should be discussed there, not here.

#89 looks good to me, though. Yeah, I guess I agree with @alex_b's rationale about keeping the second test in. It will indeed ensure that we remember to write new tests if/when that particular bug is fixed!

catch’s picture

Yes I don't see what's wrong with #89 or why non-critical feature requests need to hold this up.

sun’s picture

Reverted that.

chx’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
1.86 KB

David's concerns have been addressed, the last patch is by sun, again addressing problems -- seems we are good to go. I attached an interdiff of #88 - #95.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Committed #95 to HEAD.

I'm going to mark this closed now. I hope that it stays that way. :D

webchick’s picture

Title: Change format into string (security hole) » Change format into string
Category: bug » task
Priority: Critical » Major

Reverting status + title, I think.

mfb’s picture

Schema module is throwing a warning: filter.format is part of the primary key but is not specified to be 'not null'. Sorry I didn't yet read thru this issue, but is there some reason filter.format 'not null' changed from TRUE to FALSE?

webchick’s picture

Status: Fixed » Needs work

*sigh*

effulgentsia’s picture

Priority: Major » Critical

If it's a beta blocker, it's also critical, right?

effulgentsia’s picture

Title: Change format into string » Change format into string (primary key null)
Category: task » bug

.

chx’s picture

Status: Needs work » Reviewed & tested by the community

Given that MySQL changes NULL fields without a word this, we were already running with this patch applied so it does not require a review.


mysql> create table foo (a int null, b int null, primary key(a,b));
Query OK, 0 rows affected (0.03 sec)

mysql> show create table foo;
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
| foo   | CREATE TABLE `foo` (
  `a` int(11) NOT NULL DEFAULT '0',
  `b` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`a`,`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
chx’s picture

chx’s picture

effulgentsia asked me to patch the update too. That's totally unnecessary but for the sake of consistency I did that too. Once again: this patch does NOT change your database at all because MySQL makes your primary key NOT NULL whether you want or not.

mfb’s picture

Looks good. The schema was already silently corrected by MySQL. With this patch, the declared and actual schemas match so schema.module is happy.

webchick’s picture

Status: Reviewed & tested by the community » Needs work

Hm. The original patch has a number of update functions, each of which are setting format to 'not null' => FALSE. Methinks they should be updated as well.

To confirm this, we'd need to run schema module on a database upgraded from beta1 to HEAD.

webchick’s picture

Status: Needs work » Fixed

Ok, I get it.

It's problematic here because it's a PK field. In other modules' schemas it won't be.

I committed #105 to HEAD to remove the error. My hunch is we haven't seen the last of this issue yet, though, as not null -> FALSE seems to be a deliberate decision made for some reason up above.

Although as effulgentsia pointed out on IRC moments ago, this could've just been a copy/paste oversight since this is the "source" table for these formats in the first place, and can never be NULL.

I guess time will tell if we've heard the last of this issue or not. :)

effulgentsia’s picture

Status: Fixed » Reviewed & tested by the community

'not null' => FALSE in the other tables is probably correct, since it's not a primary key in those tables. It was likely a copy/paste error to have 'not null' => FALSE in the {filter} table itself, and not caught, given that MySQL silently corrected it. Given #106, RTBC.

effulgentsia’s picture

Status: Reviewed & tested by the community » Fixed

x-post

David_Rothstein’s picture

Title: Change format into string (primary key null) » Change format into string
Category: bug » task
Priority: Critical » Major
Status: Fixed » Reviewed & tested by the community
FileSize
2.31 KB

I really hate to do this. But.... The test from #95? It was never committed :)

webchick’s picture

#111: oh_no_reopened_again.patch queued for re-testing.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

D'oh. Thanks.

Committed to HEAD. Really, really marking fixed now. :D

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

catch’s picture

Status: Closed (fixed) » Active

Eight months later I am tempted to open this again, since it introduced a fatal error in the upgrade path for sites that had CCK module installed in D6. However instead of doing that I opened #1228488: Drupal 7 text module update (added during beta) runs on sites that have D6 CCK text module installed.

http://drupal.org/node/934050#comment-3552204 still stands.

catch’s picture

Status: Active » Closed (fixed)

So tempted, I actually did re-open it, moving back.

chx’s picture

Note that #50 was committed to core after basically a single review by sun who wrote most of it. And it broke the upgrade path? News at 11! Yay for breaking the process and the freeze!