Search module fails and produce SQL error:
PDOException: SQLSTATE[21000]: Cardinality violation: 1241 Operand should contain 1 column(s): SELECT i.type AS type, i.sid AS sid, SUM(CAST(:multiply_0 AS DECIMAL) * COALESCE(( (8,1918095044299 * i.score * t.count)), 0) / CAST(:total_0 AS DECIMAL)) AS calculated_score FROM {search_index} i INNER JOIN {node} n ON n.nid = i.sid INNER JOIN {search_total} t ON i.word = t.word INNER JOIN {search_dataset} d ON i.sid = d.sid AND i.type = d.type WHERE (n.status = :db_condition_placeholder_0) AND( (i.word = :db_condition_placeholder_1) )AND (i.type = :db_condition_placeholder_2) AND( (d.data LIKE :db_condition_placeholder_3 ESCAPE '\\') ) GROUP BY i.type, i.sid HAVING (COUNT(*) >= :matches) ORDER BY calculated_score DESC LIMIT 10 OFFSET 0; Array ( [:db_condition_placeholder_0] => 1 [:db_condition_placeholder_1] => 2011 [:db_condition_placeholder_2] => node [:db_condition_placeholder_3] => % 2011 % [:matches] => 1 [:multiply_0] => 5 [:total_0] => 5 ) в функции PagerDefault->execute() (строка 80 в файле /srv/www/hsib.msu.ru/WWW/includes/pager.inc).
This error produced in search.extender.inc, execute routine, line ~436:
$this->scores = str_replace('i.relevance', '(' . (1.0 / $this->normalize) . ' * i.score * t.count)', $this->scores);
On system locales, where decimal separator is comma, not dot, this expression gives string with float number with comma separator ....COALESCE(( (8,1918095044299 * i.score * t.count))...., which processed by MySQL with error (Cardinality violation: 1241).
So the problem is in division operation (1.0 / $this->normalize), it's necessary to replace comma by dot on locales. Something like:
$this->scores = str_replace('i.relevance', '(' . number_format(1.0 / $this->normalize, 8, '.', '') . ' * i.score * t.count)', $this->scores);
Comments
Comment #1
jhodgdonHmmm...
Looking at search.extender.inc:
So the problem is that it's assuming that a printed $score would work as a MySQL expresssion.
In this case, it appears that the caller of addScore is passing in
The question, though, is where does this ranking come from? I am not seeing it in Drupal core's node search rankings (which come from hook_ranking()). Is it possible you have a contributed module that is adding to the search rankings? The only scores added by core modules are in node_ranking(), comment_ranking(), and statistics_ranking(), and none of them appears to use i.score or t.count.
So I think this is not a Drupal Core problem, but a problem with another module you have installed.
Comment #2
damien tournoud commentedWell, we need to fix that, who though it was a good idea to use string concatenation like that? We don't have placeholders for nothing.
Comment #3
jhodgdonDamien: I don't think the problem is in Drupal Core. This function is assuming it's getting in a well-formed query as its argument, which may be stupid, but that is what the function does... and some contrib module is sending in a non-well-formed $score.
Comment #4
lmeurs commentedI think it might be a problem in core, using Drupal v7.12. It is useful to set locale manually for several projects, the
LC_ALLconstant sets locale in all categories, but uses commas as decimal separators in Dutch. This unfortunately makes MySQL trip when used in a query...kb@'s solution to use
number_format()before concatenation looks good to me.Now I set all categories but
LC_NUMERICin the following way:Comment #5
jhodgdonThis is a duplicate of #2016497: Search query extender should not use floats directly, which is newer but has a solution posted (not yet a patch but at least a suggestion).