I noticed when I have an argument validator and a filter that both restrict nodes returned based on the nodes having a certain term that there was a logic error in views_many_to_one_helper::ensure_my_table().

The table alias was being set as follows:

$this->handler->table . '_value_' . $count

but a new $count was done for each unique value of $field, not $this->handler->table, which should be what is used. That patch fixes this problem. An alternative approach would be to form the table alias name in a different way based on $field instead of $this->handler->table. So something like

$this->handler->table . '_' . $this->handler->field . '_value_' . $count

The later approach might result in prettier code, but I wasn't sure if it would cause other problems. Applying the attached patch fixes the problem I was having and doesn't seem to cause any additional problems, but I haven't tested thoroughly.

Comments

merlinofchaos’s picture

Using just the table as an identifier? That doesn't seem like it's safe; if you end up with queries on different fields within the same table don't you end up crossing things up?

aclight’s picture

Huh? That's what the code is currently doing (that is, using just the table plus a count as the identifier). The patch I uploaded doesn't change the way that the alias is created, other than it doesn't start counting from 0 with each table $field, as the current code does, but with each actual table that's used.

aclight’s picture

It's been a week with no follow up on this issue. I don't know if that means that you've been busy with other things or if you still don't see what the problem is here. On the chance that it's the later, I thought I'd be a little more explicit as to the problem.

For both examples below let's use the following situation where views_many_to_one_helper::ensure_my_table() is called twice. The first time its called,

$this->handler->table = term_node
$this->handler->field = project_type_tid

and the second time

$this->handler->table = term_node
$this->handler->field = tid

These are real values that come from a custom relationship (first one) and the Term:tid filter that ships with views (second one).

The current relevant code is this:

          if (!isset($this->handler->view->many_to_one_aliases[$field][$value])) {
            if (!isset($this->handler->view->many_to_one_count[$field])) {
              $this->handler->view->many_to_one_count[$field] = 0;
            }
            $this->handler->view->many_to_one_aliases[$field][$value] = $this->handler->table . '_value_' . ($this->handler->view->many_to_one_count[$field]++);
          }
          $alias = $this->handler->table_aliases[$value] = $this->add_table($join, $this->handler->view->many_to_one_aliases[$field][$value]);
// .....

So the first time this code is called, $this->handler->view->many_to_one_count[$field] will not be set, the counter will be set to 0, and therefore $this->handler->view->many_to_one_aliases[$field][$value] will be set to term_node_value_0. That's all fine. But then the second time this is called, $this->handler->view->many_to_one_count[$field] will also be unset (because this time $field is 'tid' where before it was 'project_type_tid'. That means that a new counter will be used, and it will be reset to 0, and therefore the second time ensure_my_table() is called $this->handler->view->many_to_one_aliases[$field][$value] will again be set to term_node_value_0.

The reason is that only $this->handler->table is concatenated into a string to produce what will be the alias, and in this example both times this function is called this will be equal to "term_node".

Hopefully this clears up what the problem is.

merlinofchaos’s picture

AHHHH! I get it now. Man it took me a long time to zero in on what the problem was.

What if we used $handler->real_field instead of $handler->field? I am concerned that just using the table, if we have a single table where actually different fields are in use like this, we could get different collisions.

$handler->real_field should always be the unaliased field, which would allow this to work. What do you think?

(And yes, part of this is that I haven't had a lot of time; I'm trying to get Panels 3 out and right now I'm in a tough piece of work and being pulled in 8 different directiosn every day)

yched’s picture

Right, generating an alias string that discriminates different fields looks safer that storing $counts based on the table as the initial patch does. Wouldn't know for sure about using field vs real_field, though.

merlinofchaos’s picture

$handler->real_field will always be the actual, unaliased field a handler thinks it belongs to assuming such a thing exists (and if it's using many::one it better exist).

marcp’s picture

I think what's missing from aclight's description in #3 is this, at the beginning of views_many_to_one_helper::ensure_my_table():

      // For 'or' if we're not reducing duplicates, we get the absolute simplest:
      $field = $this->handler->table . '.' . $this->handler->field;

So, from his example, the first time through, $field is 'term_node.project_type_tid' and the second time through, $field is 'term_node.tid' which, since both fields are from the same table, should get them the same alias.

merlinofchaos’s picture

Status: Needs review » Fixed

Ok, finally convinced. This is now in.

Status: Fixed » Closed (fixed)

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