since upgrading to mysql Ver 14.14 Distrib 5.1.39, my log is reporting numerous errors like those below. I've tried resetting the index, with no change. MySQL tables have been analyized, optimized, and repaired, too.

Duplicate entry '268' for key 'PRIMARY' query: INSERT INTO search_total (word, count) VALUES ('268', 0.30102999566398) in /var/www/www.sterndata.com/drupal-6.14/modules/search/search.module on line 290.

Duplicate entry 'palmrest' for key 'PRIMARY' query: INSERT INTO search_total (word, count) VALUES ('palmrest', 0.30102999566398) in /var/www/www.sterndata.com/drupal-6.14/modules/search/search.module on line 290.

CommentFileSizeAuthor
#6 638702.patch1.6 KBjhodgdon
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kribby’s picture

Subscribing

jhodgdon’s picture

Can you try going to the Search settings page and clicking on the link that rebuilds the search index, and then running cron from the Status Report page until Search reports that everything is indexed?

sterndata’s picture

Nope. Still get errors when a page is updated after the index is rebuilt.

jhodgdon’s picture

That's very interesting. I'm looking at those lines in the search module code:

    db_query("UPDATE {search_total} SET count = %f WHERE word = '%s'", $total, $word);
    if (!db_affected_rows()) {
      db_query("INSERT INTO {search_total} (word, count) VALUES ('%s', %f)", $word, $total);
    }

In other words, it is first doing an UPDATE query to try to update an existing row in the search total table. And then if the UPDATE says "No rows were affected", it's assuming that the word was not in the database table, and trying to use an INSERT query instead.

So it looks like the db_affected_rows() function is not working correctly for you: it should be reporting that it updated that row, and instead it is reporting that it updated nothing.

Very interesting....

So we need to investigate why db_affected_rows() isn't doing the right thing, but in the meantime I think you can probably ignore those errors, because the UPDATE probably worked.

jhodgdon’s picture

Hah! I think I have possibly found the answer. From the documentation of the PHP function mysql_affected_rows():

When using UPDATE, MySQL will not update columns where the new value is the same as the old value. This creates the possibility that mysql_affected_rows() may not actually equal the number of rows matched, only the number of rows that were literally affected by the query.

So possibly this is the issue. If the index is being rebuilt and the count is the same as it was before, it's possible that the affected row count will be zero.

jhodgdon’s picture

FileSize
1.6 KB

Looking at the code base for Drupal 6, I see that in most cases, when db_affected_rows() is used to figure out if an update took place, the next INSERT statement is preceded by @ to suppress the error that could result when the insert figures out the row actually did exist. This was not done in two places: the search module being one of them. Here's a patch to remedy that.

jhodgdon’s picture

Status: Active » Needs review
jhodgdon’s picture

Example of another place it's done this way in Drupal 6:

function variable_set($name, $value) {
  global $conf;

  $serialized_value = serialize($value);
  db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name);
  if (!db_affected_rows()) {
    @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value);
  }

  cache_clear_all('variables', 'cache');

  $conf[$name] = $value;
}

Status: Needs review » Needs work

The last submitted patch, 638702.patch, failed testing.

jhodgdon’s picture

Version: 6.14 » 6.x-dev
Status: Needs work » Needs review

Huh, I didn't know we had testing now for D6 patches. This patch applies fine for me. I'll try changing the version.

jhodgdon’s picture

#6: 638702.patch queued for re-testing.

jhodgdon’s picture

I just filed a related issue about what the return value should be for D7 update queries (because the same problem exists there):
#718540: Better documentation in query.inc

ti2m’s picture

Ehm,
so the solution to this is to supress the warning??? Then we could just skip the whole if clause in general. Other option would be to do something like

if (!db_fetch_object(db_query("SELECT count FROM {search_total} WHERE word = '%s'", $word))) {

(could probably be done in a nicer way)
to replace

if (!db_affected_rows()) {
jhodgdon’s picture

PeterP - Right, it bothers me too, but it's definitely the pattern elsewhere in Drupal 6 core. What you're suggesting would be better, but less efficient, as it would require another query.

francisconi.org’s picture

Subscribing..

brianmercer’s picture

I just started getting the same error as the op since upgrading to Ubuntu 10.04 lucid with mysql Ver 14.14 Distrib 5.1.41.

The patch at #6 applied fine to Pressflow 6.16.77 and stopped the error messages.

Thanks.

Damien Tournoud’s picture

Status: Needs review » Reviewed & tested by the community

This makes sense, even if I cannot explain why this shows up so late in the game.

cdale’s picture

I too am getting this since my lucid upgrade, but only with mysqli. mysql seems to work as before. Perhaps the flags passed to mysqli_real_connect() are not respected anymore?

simg’s picture

I'm pretty sure this problem is caused by a bug in the db_affected_rows() function.

I've reported the bug and post a suggested fix (that works) here.

http://drupal.org/node/805858

I don't have "commit" access to fix the CVS version.

This bug seems to be the cause of a number of errors in the issue queue ?

Incidently, suppressing the warning is not a good solution at all (sorry)!

jhodgdon’s picture

#798626: Cron produces duplicate entry error in search.module just marked as a duplicate of this issue.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

@PeterP: that would run at least two queries: a SELECT and an INSERT/UPDATE, while our current code only runs one UPDATE query if possible or an INSERT if the update failed.

@simg: the db_affected_rows() function works as named and documented. It returns 0 when the row was updated to be the same and we pay a little performance penalty in that case, however your suggested patch in the linked issue makes us pay a penalty at all invocations of the function.

Committed, thank you.

AlexisWilke’s picture

Gábor Hojtsy,

Note that you are making improper use of the db_affacted_rows() function:

...
if (!db_affected_rows()) {
...

As you can see here: http://api.drupal.org/api/function/db_affected_rows/6 the function may return -1 which means TRUE in your situation. You ought to use > 0 instead.

...
if (db_affected_rows() > 0) {
...

Or have the Core people change the code and check for the return value, if -1, return 0.

Thank you.
Alexis Wilke

Gábor Hojtsy’s picture

@AlexisWilke: this seems like both a documentation omission and a code problem if that is the case. Where did you open an issue for these?

Status: Fixed » Closed (fixed)

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