…/modules/node/node.module and failed SELECT behind the site search box triggered by node_cron_comments_scale == 'INF'

If there's a problem with 'node_cron_comments_scale' (or with cron?), it can potentially arrive back as 'INF' (infinite?) (from MySQL via cron?) and when it does, the following block stuffs the INF into the query, and the SELECT behind the search box goes off the rails.

The following block of code is extracted from node.module shows a $scale assignment (hack) that suppresses the SELECT error.

      if (module_exists('comment') && $weight = (int)variable_get('node_rank_comments', 5)) {
        // Inverse law that maps the highest reply count on the site to 1 and 0 to 0.
        $scale = variable_get('node_cron_comments_scale', 0.0);
$scale = 0.0;
        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + c.comment_count * %f))';
        $arguments2[] = $weight;
        $arguments2[] = $scale;
        if (!$stats_join) {
          $join2 .= ' LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
        }
        $total += $weight;
      }

For reference, here is what the error from a failed search (big red box) looks like this:

* user warning: Unknown column 'INF' in 'field list' query: CREATE TEMPORARY TABLE temp_search_results SELECT i.type, i.sid, 5 * (50.73595434091 * i.relevance) + 5 * POW(2, (GREATEST(n.created, n.changed, c.last_comment_timestamp) - 1172979726) * 
6.43e-8) + 5 * (2.0 - 2.0 / (1.0 + c.comment_count * 1)) + 5 * (2.0 - 2.0 / (1.0 + nc.totalcount * -INF)) 
AS score FROM temp_search_sids i INNER JOIN search_dataset d ON i.sid = d.sid AND i.type = d.type 
INNER JOIN node n ON n.nid = i.sid LEFT JOIN node_comment_statistics c ON c.nid = i.sid 
LEFT JOIN node_counter nc ON nc.nid = i.sid WHERE (d.data LIKE '% openvms %') ORDER BY score DESC in /Library/WebServer/Documents/drupal/includes/database.mysql.inc on line 172.
* user warning: Table 'db.temp_search_results' doesn't exist query: SELECT COUNT(*) FROM temp_search_results in /Library/WebServer/Documents/drupal/includes/database.mysql.inc on line 172.

Versions:

  • Drupal 5.1
  • Apache/1.3.33 (Darwin) mod_jk/1.2.6 DAV/1.0.3 mod_ssl/2.8.24 OpenSSL/0.9.7l PHP/4.4.4 mod_perl/1.29
  • mysqladmin Ver 8.41 Distrib 4.1.22

Comments

robertdouglass’s picture

This is very unclear. The first code you submit shouldn't ever get executed:

if (module_exists('comment')

That alone should keep it from running. And it would only run on a search query anyway. Please provide more clues about what's going on, thanks.

Hoff’s picture

Drupal goes into the weeds on occasion, with no obvious trigger, and — once it gets into this state — every search fails.

The proximate trigger is a search (for anything), and once one goes wrong all of which fail with the cited red box error.

The error in the red box is always the 'INF' string embedded in the SELECT query.

Sometimes purging the search database and reloading it via cron seems to cure the problem.

cron is run manually at present.

Something upstream is loading the $scale variable with 'INF'.

This really smells like an uninitialized variable somewhere, or a version-level difference in what gets returned.

(If I could provide a reproducer, I would have done so. I have found that the specified hack seems to have cured the most recent round of problems. I'd love to cite chapter and verse and reproducer — was that available, the fix would have been queued. I'm just sorting out the internals of Drupal.)

The bug has hit earlier and on multiple occasions, and I've recently had the cycles to dig into it. Here's the earlier report 78102.

robertdouglass’s picture

Project: Node Comments » Drupal core
Version: 5.x-1.x-dev » 5.1
Component: Code » search.module

It looks like you're having a division by zero error. Take out the extra line ($scale = 0) that you added, and make sure to go to your search settings page and set the scoring factor for comments to something other than zero. This is definitely not a nodecomment module problem, though, so I'm going to reassign it to drupal.search.

Hoff’s picture

Division by zero? It may well be, but that is well upstream of this section of code somewhere, and probably around the calculation of or the assignment of the node_cron_comments_scale variable.

This particular php code clearly constructs part of the search select query, and the specific $scale looks to multiply by floating zero, which obviously clobbers the factor.

Having it floating zeroed out bothers me far less than having the 'INF' string embedded in the query in the position of the , as having 'INF' in the query derails the entire search. To wit: (2.0 - 2.0 / (1.0 + nc.totalcount * -INF)) This implies the INF string (negative INF, in this case) is arriving via $scale, which back-tracks pretty quickly to the node_cron_comments_scale variable. I haven't back-tracked what code assigns that value.

The assignment overwrites the 'INF' that is occasionally arriving in the query.

As for the search weights, the values for Keyword relevance, Recently posted, Number of comments, Number of views are each set to 5.

Hoff’s picture

Here's a fix — some might use reasonably “workaround” here — for use within node.module. This code adds a pair of is_infinite checks into the sequence, and suppresses the errors. This has been in production use for over a month now with Drupal 5.1 and replicated into the local 5.2 within a couple of days of that release, with no untoward effects and with no re-occurrences of the original INF errors. This code is also now operating on PHP 5.2.2, as well, though should operate on the original PHP.

      if (module_exists('comment') && $weight = (int)variable_get('node_rank_comments', 5)) {
        // Inverse law that maps the highest reply count on the site to 1 and 0 to 0.
        $scale = variable_get('node_cron_comments_scale', 0.0);
        if (is_infinite($scale))
          $scale = 0.0;
        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + c.comment_count * %f))';

…and a little further along…

      if (module_exists('statistics') && variable_get('statistics_count_content_views', 0) &&
          $weight = (int)variable_get('node_rank_views', 5)) {
        // Inverse law that maps the highest view count on the site to 1 and 0 to 0.
        $scale = variable_get('node_cron_views_scale', 0.0);        
        if (is_infinite($scale)) 
          $scale = 0.0;
        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + nc.totalcount * %f))';

Current versions:

  • Drupal 5.2
  • Apache/1.3.33 (Darwin) PHP/5.2.2 mod_jk/1.2.6 DAV/1.0.3 mod_ssl/2.8.24 OpenSSL/0.9.7l mod_perl/1.29
  • MySQL 4.1.22
jhodgdon’s picture

Status: Active » Closed (won't fix)

7.0 is out tomorrow, 5.x is obsolete, won't fix, sorry.