The admin/node/book/n function does not display the weight in book_admin_view_book - I think for all node types other than "book" (i have a number of node types i have added myself, and the problem exists for type "story" or "image"). The weight always appears as zero.
This is because of this code

function book_admin_view_book($nid, $depth = 1) {
  $result = db_query(db_rewrite_sql('SELECT n.nid, b.weight, n.title FROM {node} n INNER JOIN {book} b 
ON n.nid = b.nid WHERE b.parent = %d ORDER BY b.weight, n.title'), $nid);

  $rows = array();

  while ($node = db_fetch_object($result)) {
//    $node = node_load(array('nid' => $node->nid));
    $rows[] = book_admin_view_line($node, $depth);
    $rows = array_merge($rows, book_admin_view_book($node->nid, $depth + 1));
  }

  return $rows;
}

Note the line I have commented out. I'm just a beginner here but i cannot work out why we need to do a node_load after we have just read all the info we require in the db_query to build the quite simple display. It generates huge extra processing for no effect I can see. In fact the bug disappears when i comment it out. $node->weight has correct value before the node_load call. After the call it is still there for node type of "book", it is null for other node types. So the displayed value defaults to "0". So why have the call?

Commenting out the call fixes the bug.

With the bug there, the result is not just a wrong display of the value. The result is the incorrect "0" value gets written back to the database, trashing whatever value was there. Why? Because of this code:

function book_admin_save($bid, $edit = array()) {
  if ($bid) {
    $book = node_load(array('nid' => $bid));

    foreach ($edit as $nid => $value) {
      // Check to see whether the title needs updating:
      $title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
      if ($title != $value['title']) {
        db_query("UPDATE {node} SET title = '%s' WHERE nid = %d", $value['title'], $nid);
      }

      // Check to see whether the weight needs updating:
      $weight = db_result(db_query('SELECT weight FROM {book} WHERE nid = %d', $nid));
      if ($weight != $value['weight']) {
        db_query('UPDATE {book} SET weight = %d WHERE nid = %d', $value['weight'], $nid);
      }
    }

To test whether the value has changed and needs to be saved it re-reads the database, gets the correct weight, compares it to the incorrect displayed "0", and writes the bad "0" back!!!! When I went to school we'd have stashed the "0" value in memory when we built the display, not done all these database calls to get it again, thus saving a lot of overhead and incidentally not causing this problem either. there is no bug in this second snippet but it seems costly. I guess I'm biased against it because it erased the weights i had painstakingly added to about 40 nodes in one big book :-)

Comments

steph’s picture

For me, it seems to work fine with Drupal CVS as of today.

I am not expert, but i think it is better to use node_load because this function *can* do some processing after or before the sql queries. Optimisation should be done in this function (and i guess it is fairly good).

twohills’s picture

The node_load question is the kind of debate one has over a beer :-)

I tested against my 4.6.5 install directories and the problem is there. I've fixed it on my site and it's good to know it's not there in 4.7. At least this issue stands as a warning to other 4.6 users; I lost a half-hour's work and spent a couple more working out why....

magico’s picture

Version: 4.6.5 » 4.6.9
Status: Active » Needs work

Deserves a patch?

magico’s picture

Version: 4.6.9 » 4.7.3
Status: Needs work » Active

This bug is reproducible in 4.7.3

magico’s picture

Version: 4.7.3 » 5.x-dev
Status: Active » Fixed
Anonymous’s picture

Status: Fixed » Closed (fixed)