Last night, I upgrade to the latest date module from CVS for branch DRUPAL-5--2.

Then all my calendar views broke! And they broke bad... the calendar was suddenly empty.

When I reverted to a backup from Apr 7 18:29 (Chicago), everything cleared up and my calendar views worked again.

It's a Sunday, so I really don't want to spend the day figuring out why the latest CVS checkout broke my views. I'll get on it tomorrow.

CommentFileSizeAuthor
#14 date2.filter.patch744 bytesdopry
#14 devel.escaped_view_query.patch815 bytesdopry
#4 views-mysql-fix.patch904 bytesAnonymous (not verified)

Comments

Anonymous’s picture

Title: Views constructs bad queries with date fields, breaks calendars » Date fields in views broken.

Nobody else is having trouble with date fields in their views?

The field works fine in my content. The date can be edited, saved, created. However, the queries that views generates are not retrieving any nodes.

Here's a query generated by the calendar view with the latest version of Date module (DRUPAL-5--2):

SELECT node.nid, node.title AS node_title, node.changed AS node_changed, CONCAT(STR_TO_DATE(node_data_field_date.field_date_value, '%Y-%m-%%%%dT%T'),'|',STR_TO_DATE(node_data_field_date.field_date_value2, '%Y-%m-%%%%dT%T')) AS node_data_field_date_field_date_value, node_data_field_date.field_date_value2 AS node_data_field_date_field_date_value2, node_data_field_date.field_date_timezone AS node_data_field_date_field_date_timezone, node_data_field_date.field_date_offset AS node_data_field_date_field_date_offset, node_data_field_date.field_date_offset2 AS node_data_field_date_field_date_offset2, node.type FROM {node} node LEFT JOIN {content_type_event} node_data_field_date ON node.vid = node_data_field_date.vid WHERE (%s.%s %s '%s') AND ((STR_TO_DATE(node_data_field_date.field_date_value2, '%Y-%m-%%%%dT%T') >='2007-12-31 00:00:00' AND STR_TO_DATE(node_data_field_date.field_date_value, '%Y-%m-%%%%dT%T') <='2008-01-01 23:59:59'))

Here's the query generated by the same view, same version after I reverted to an earlier version of Date module (from April 7):

SELECT node.nid, node.title AS node_title, node.changed AS node_changed, CONCAT(( REPLACE(node_data_field_date.field_date_value,'T',' ') + INTERVAL (node_data_field_date.field_date_offset) SECOND),'|',( REPLACE(node_data_field_date.field_date_value2,'T',' ') + INTERVAL (node_data_field_date.field_date_offset) SECOND)) AS node_data_field_date_field_date_value, node_data_field_date.field_date_value2 AS node_data_field_date_field_date_value2, node_data_field_date.field_date_timezone AS node_data_field_date_field_date_timezone, node_data_field_date.field_date_offset AS node_data_field_date_field_date_offset, node_data_field_date.field_date_offset2 AS node_data_field_date_field_date_offset2, node.type FROM {node} node LEFT JOIN {content_type_event} node_data_field_date ON node.vid = node_data_field_date.vid WHERE (%s.%s %s '%s') AND ((( REPLACE(node_data_field_date.field_date_value2,'T',' ') + INTERVAL (node_data_field_date.field_date_offset) SECOND) >='2007-12-31 00:00:00' AND ( REPLACE(node_data_field_date.field_date_value,'T',' ') + INTERVAL (node_data_field_date.field_date_offset) SECOND) <='2008-01-01 23:59:59'))
karens’s picture

Title: Date fields in views broken. » Update Calendar for recent Date Views changes.
Project: Date » Calendar

This is not a Date problem, this is a Calendar problem. The Calendar module needs to be updated for a recent change in the Date API.

Anonymous’s picture

All views on my development site that use date fields are broken. Not just calendar views. Sorry, I'm just now really getting into this problem.. my earlier reports are shallow with facts.

Anonymous’s picture

Title: Update Calendar for recent Date Views changes. » Date fields in views broken.
Project: Calendar » Date
Status: Active » Needs review
StatusFileSize
new904 bytes

Yup. it's definitely a date bug, because I fixed it! It was quite a puzzler, that's for sure.

There's also a likely fix for a bug which I didn't encounter. It just screamed "typo" of the sort that caused this bug. Perhaps there's some funny escaping going on with a text editor somewhere?

karens’s picture

Status: Needs review » Postponed (maintainer needs more info)

No, that escaping is needed to keep the query from being mangled by Drupal's query builder. I still need to make some changes on the Calendar module side to use the new code, and it's possible there are other date queries that still need work. The date field filters now work correctly with that code, but I haven't made my way to every possible place that might be affected.

When you say 'all views are broken', I need more information about Date-only views (not Calendar views) that are still broken. I know the Calendar Views are broken and plan to work on them next.

Anonymous’s picture

KarenS,

I think there were too many % in the STR_TO_DATE function for MySQL. After passing through the query builder, the output would have been %%d when we need it to be just %d. That made the field always NULL in the query.

The patch definitely fixes the problem I was having. Is it wrong?

karens’s picture

The current code produces exactly the right result when creating views date filters and your patch would break them.

You haven't given me any information on what queries you're seeing that are broken with the current code and fixed by your patch so I have no way to do anything else with this. I need something reproducable -- like a view export with a cut and paste of the query that it creates that is wrong. Plus it may be that this is system-related, so info on what version of PHP and mysql you're using might help.

Anonymous’s picture

KarenS,

The queries are here. Here's the query built by an unpatched Date_api_sql.inc:

SELECT DISTINCT(node.nid), node.title AS node_title, node.changed AS node_changed, CONCAT(STR_TO_DATE(node_data_field_date.field_date_value, '%Y-%m-%%dT%T'),'|',STR_TO_DATE(node_data_field_date.field_date_value2, '%Y-%m-%%dT%T')) AS node_data_field_date_field_date_value, node_data_field_date.field_date_value2 AS node_data_field_date_field_date_value2, node_data_field_date.field_date_timezone AS node_data_field_date_field_date_timezone, node_data_field_date.field_date_offset AS node_data_field_date_field_date_offset, node_data_field_date.field_date_offset2 AS node_data_field_date_field_date_offset2, node.type FROM node node LEFT JOIN content_type_event node_data_field_date ON node.vid = node_data_field_date.vid WHERE (node.status = '1') AND ((STR_TO_DATE(node_data_field_date.field_date_value2, '%Y-%m-%%dT%T') >='2008-03-31 00:00:00' AND STR_TO_DATE(node_data_field_date.field_date_value, '%Y-%m-%%dT%T') <='2008-05-01 23:59:59'))

And here's the query generated with my patch applied:

SELECT DISTINCT(node.nid), node.title AS node_title, node.changed AS node_changed, CONCAT(STR_TO_DATE(node_data_field_date.field_date_value, '%Y-%m-%dT%T'),'|',STR_TO_DATE(node_data_field_date.field_date_value2, '%Y-%m-%dT%T')) AS node_data_field_date_field_date_value, node_data_field_date.field_date_value2 AS node_data_field_date_field_date_value2, node_data_field_date.field_date_timezone AS node_data_field_date_field_date_timezone, node_data_field_date.field_date_offset AS node_data_field_date_field_date_offset, node_data_field_date.field_date_offset2 AS node_data_field_date_field_date_offset2, node.type FROM node node LEFT JOIN content_type_event node_data_field_date ON node.vid = node_data_field_date.vid WHERE (node.status = '1') AND ((STR_TO_DATE(node_data_field_date.field_date_value2, '%Y-%m-%dT%T') >='2008-03-31 00:00:00' AND STR_TO_DATE(node_data_field_date.field_date_value, '%Y-%m-%dT%T') <='2008-05-01 23:59:59'))

The key difference is in STR_TO_DATE. The unpatched date makes a query that has an extra percent sign, which is coming from the quadruple escaping of the 'd' placeholder.

karens’s picture

I need to know where that query is getting constructed in order to do anything with this. Is it coming from a View, and which one, and how is the view set up? The query is created by a handler and I need to know which handler is being used. The handlers I am testing are producing the right result. Apparently you are using a handler that isn't, so I have to know where this is coming from.

Anonymous’s picture

KarenS.

All of my views with date fields are affected. If I bring Calendar into the situation, it may just confuse things. Here is a view that I'm using to display valid items of a particular type. Validity is determined by comparing a date field to now(). I apologize if I'm giving you too much information, but I am not sure how to find out which handler I am using.

  $view = new stdClass();
  $view->name = 'action_alerts';
  $view->description = 'Valid action alerts';
  $view->access = array (
);
  $view->view_args_php = '';
  $view->page = TRUE;
  $view->page_title = 'Action Alerts';
  $view->page_header = '';
  $view->page_header_format = '1';
  $view->page_footer = '';
  $view->page_footer_format = '1';
  $view->page_empty = '';
  $view->page_empty_format = '1';
  $view->page_type = 'node';
  $view->url = 'issue/action-alerts';
  $view->use_pager = TRUE;
  $view->nodes_per_page = '10';
  $view->menu = TRUE;
  $view->menu_title = 'Action Alerts';
  $view->menu_tab = FALSE;
  $view->menu_tab_weight = '0';
  $view->menu_tab_default = FALSE;
  $view->menu_tab_default_parent = NULL;
  $view->menu_tab_default_parent_type = 'tab';
  $view->menu_parent_tab_weight = '0';
  $view->menu_parent_title = '';
  $view->block = TRUE;
  $view->block_title = 'Action Alerts';
  $view->block_header = '';
  $view->block_header_format = '1';
  $view->block_footer = '';
  $view->block_footer_format = '1';
  $view->block_empty = '';
  $view->block_empty_format = '1';
  $view->block_type = 'teaser';
  $view->nodes_per_block = '5';
  $view->block_more = TRUE;
  $view->block_use_page_header = FALSE;
  $view->block_use_page_footer = FALSE;
  $view->block_use_page_empty = FALSE;
  $view->sort = array (
    array (
      'tablename' => 'node',
      'field' => 'sticky',
      'sortorder' => 'DESC',
      'options' => '',
    ),
    array (
      'tablename' => 'node',
      'field' => 'created',
      'sortorder' => 'DESC',
      'options' => 'normal',
    ),
  );
  $view->argument = array (
  );
  $view->field = array (
  );
  $view->filter = array (
    array (
      'tablename' => 'node',
      'field' => 'status',
      'operator' => '=',
      'options' => '',
      'value' => '1',
    ),
    array (
      'tablename' => 'node',
      'field' => 'type',
      'operator' => 'OR',
      'options' => '',
      'value' => array (
  0 => 'action_alert',
),
    ),
    array (
      'tablename' => 'node_data_field_valid',
      'field' => 'field_valid_value_default',
      'operator' => '<=',
      'options' => 'now',
      'value' => '',
    ),
    array (
      'tablename' => 'node_data_field_valid',
      'field' => 'field_valid_value_to|default',
      'operator' => '>=',
      'options' => 'now',
      'value' => '',
    ),
  );
  $view->exposed_filter = array (
  );
  $view->requires = array(node, node_data_field_valid);
  $views[$view->name] = $view;

With my patch, the query produced (for the page view) is:

SELECT DISTINCT(node.nid), node.sticky AS node_sticky, node.created AS node_created_created FROM node node LEFT JOIN content_type_action_alert node_data_field_valid ON node.vid = node_data_field_valid.vid WHERE (node.status = '1') AND (node.type IN ('action_alert')) AND (STR_TO_DATE(node_data_field_valid.field_valid_value, '%Y-%m-%dT%T') <= NOW()) AND (STR_TO_DATE(node_data_field_valid.field_valid_value2, '%Y-%m-%dT%T') >= NOW()) ORDER BY node_sticky DESC, node_created_created DESC LIMIT 0, 10

However the latest checkout makes this query:

SELECT DISTINCT(node.nid), node.sticky AS node_sticky, node.created AS node_created_created FROM node node LEFT JOIN content_type_action_alert node_data_field_valid ON node.vid = node_data_field_valid.vid WHERE (node.status = '1') AND (node.type IN ('action_alert')) AND (STR_TO_DATE(node_data_field_valid.field_valid_value, '%Y-%m-%%dT%T') <= NOW()) AND (STR_TO_DATE(node_data_field_valid.field_valid_value2, '%Y-%m-%%dT%T') >= NOW()) ORDER BY node_sticky DESC, node_created_created DESC LIMIT 0, 10

%Y-%m-%%dT%T for a date format looks wrong to me. It has an extra %.

I'm using PHP 5.2, MySQL 5... standard Debian stable packages.

karens’s picture

Status: Postponed (maintainer needs more info) » Fixed

Fixed in latest commit. Thanks!

karens’s picture

Status: Fixed » Active

Marked wrong issue. I can't reproduce this though, the query works fine for me with the code as-is, so this needs more investigation.

Anonymous’s picture

Ok. Please let me know what I can do to continue to diagnose the problem.

dopry’s picture

Status: Active » Needs review
StatusFileSize
new815 bytes
new744 bytes

@KarenS,
The latest DRUPAL-5--2 HEAD seems to have a double escaping for the STR_TO_DATE....

here is the view so you can see how the view is configured, it does use calendar, but calendar only provides an output handler for views as far as I can tell...

 $view = new stdClass();
  $view->name = 'dpg_calendar';
  $view->description = 'The DPG calendar section.';
  $view->access = array (
);
  $view->view_args_php = '';
  $view->page = TRUE;
  $view->page_title = 'Calendar';
  $view->page_header = '';
  $view->page_header_format = '1';
  $view->page_footer = '';
  $view->page_footer_format = '1';
  $view->page_empty = '';
  $view->page_empty_format = '1';
  $view->page_type = 'calendar';
  $view->url = 'calendar';
  $view->use_pager = FALSE;
  $view->nodes_per_page = '0';
  $view->block = TRUE;
  $view->block_title = 'Calendar';
  $view->block_header = '';
  $view->block_header_format = '1';
  $view->block_footer = '';
  $view->block_footer_format = '1';
  $view->block_empty = '';
  $view->block_empty_format = '1';
  $view->block_type = 'calendar';
  $view->nodes_per_block = '999';
  $view->block_more = TRUE;
  $view->block_use_page_header = FALSE;
  $view->block_use_page_footer = FALSE;
  $view->block_use_page_empty = FALSE;
  $view->sort = array (
  );
  $view->argument = array (
    array (
      'type' => 'calendar_year',
      'argdefault' => '2',
      'title' => '%1',
      'options' => '',
      'wildcard' => '',
      'wildcard_substitution' => '',
    ),
    array (
      'type' => 'calendar_month',
      'argdefault' => '2',
      'title' => '%2',
      'options' => '',
      'wildcard' => '',
      'wildcard_substitution' => '',
    ),
    array (
      'type' => 'calendar_day',
      'argdefault' => '2',
      'title' => '%3',
      'options' => '',
      'wildcard' => '',
      'wildcard_substitution' => '',
    ),
  );
  $view->field = array (
    array (
      'tablename' => 'node',
      'field' => 'title',
      'label' => 'Title:',
      'handler' => 'views_handler_field_nodelink',
      'options' => 'link',
    ),
    array (
      'tablename' => 'node_data_field_start',
      'field' => 'field_start_value',
      'label' => '',
      'handler' => 'content_views_field_handler_ungroup',
      'options' => 'default',
    ),
  );
  $view->filter = array (
    array (
      'tablename' => 'node',
      'field' => 'status',
      'operator' => '=',
      'options' => '',
      'value' => '1',
    ),
    array (
      'tablename' => 'node',
      'field' => 'type',
      'operator' => 'OR',
      'options' => '',
      'value' => array (
  0 => 'event',
),
    ),
  );
  $view->exposed_filter = array (
  );
  $view->requires = array(node, node_data_field_start);
  $views[$view->name] = $view;

Where clause before patch:
ADDTIME(STR_TO_DATE(node_data_field_start.field_start_value, '%Y-%m-%%%%dT%T'), SEC_TO_TIME(28800)) <='2008-01-01 23:59:59'))

Escaped where clause before patch*:
ADDTIME(STR_TO_DATE(node_data_field_start.field_start_value, '%Y-%m-%%dT%T'), SEC_TO_TIME(28800)) <='2008-01-01 23:59:59'))

Mysql Says:

+---------------------------------------------------------------------------------------------------+
| ADDTIME(STR_TO_DATE(node_data_field_start.field_start_value, '%Y-%m-%%dT%T'), SEC_TO_TIME(28800)) |
+---------------------------------------------------------------------------------------------------+
| NULL                                                                                              | 
| NULL                                                                                              | 

Where clause after patch:
ADDTIME(STR_TO_DATE(node_data_field_start.field_start_value, '%Y-%m-%%dT%T'), SEC_TO_TIME(28800)) <='2008-01-01 23:59:59'))

Escaped where clause after patch*:
ADDTIME(STR_TO_DATE(node_data_field_start.field_start_value, '%Y-%m-%dT%T'), SEC_TO_TIME(28800)) <='2008-01-01 23:59:59'))

Mysql Says:

+--------------------------------------------------------------------------------------------------+
| ADDTIME(STR_TO_DATE(node_data_field_start.field_start_value, '%Y-%m-%dT%T'), SEC_TO_TIME(28800)) |
+--------------------------------------------------------------------------------------------------+
| 2008-04-01 18:00:00                                                                              | 

* I've also attached the patch I use on devel to see escaped queries. DRUPAL-5

karens’s picture

The problem is that on my system I need the extra escaping or the values get mangled -- '%d' becomes '0' by the time it gets to MYSQL. I'm trying to figure out exactly where and why that is happening.

dopry’s picture

db_rewrite_sql/hook_rewrite_sql would be a good place to look for such insanity... at least its a pattern to start with.

BrianKlinger’s picture

Hello, KarenS. I was glancing through this and noticed you mentioning your trouble with %d. There was a problem with this in Views that Merlinofchaos created a patch for and that took care of the views (the issue surfaced somewhere in the 5.4-5.7 upgrades - I don't remember for sure which one it was). I don't know if this is the same thing or if this helps you at all, but here's the link to the issue, patch, and subsequent comments/discussion. http://drupal.org/node/165611

karens’s picture

Found the culprit, now I need to think of the best solution.

The problem is there is a Views function, _views_replace_args(). _views_replace_args() runs the Views query through _db_query_callback(), and it gets run through _db_query_callback() again in db_query(). So any view that triggers that Views function needs double escaping to work right. If I keep that Views function from doing its replacements, my queries work correctly with the normal escaping. If you create SQL outside of Views, the double escaping will not work right, of course, and there may be some Views that don't trigger that function and the double escaping won't work right there, either, so I need to find a way to make the SQL work right whether or not it runs through that function.

karens’s picture

I've come up with a possible solution for this using Views substitutions that will be fixed by my filter fix in http://drupal.org/node/247752. I'm going to swap out all '%%d' values in the pre_query and swap them back in using Views substitutions. That seems to get them safely through Views processing.

karens’s picture

Status: Needs review » Fixed

More info on this problem. The problems with the escaping come from a Views bug that was fixed in January but the fix is not in the official release. So the double escaping was needed for this to work with the latest official Views release, but it broke in the latest Views dev version. I was testing with the latest official release, so I needed the double escaping, when I switch to the dev version things work fine without it.

The good news is that the bug is fixed and my work-around isn't needed so long as you are using the dev version of Views.

Anonymous’s picture

Status: Fixed » Closed (fixed)

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