? drupal-512962-D6.patch
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.255.2.32
diff -u -p -r1.255.2.32 menu.inc
--- includes/menu.inc	6 Oct 2009 11:59:05 -0000	1.255.2.32
+++ includes/menu.inc	9 Jan 2010 00:25:59 -0000
@@ -579,7 +579,7 @@ function _menu_translate(&$router_item, 
   $router_item['href'] = implode('/', $link_map);
   $router_item['options'] = array();
   _menu_check_access($router_item, $map);
-  
+
   // For performance, don't localize an item the user can't access.
   if ($router_item['access']) {
     _menu_item_localize($router_item, $map);
@@ -1880,7 +1880,7 @@ function _menu_delete_item($item, $force
  *   - plid        The mlid of the parent.
  *   - router_path The path of the relevant router item.
  * @return
- *   The mlid of the saved menu link, or FALSE if the menu link could not be 
+ *   The mlid of the saved menu link, or FALSE if the menu link could not be
  *   saved.
  */
 function menu_link_save(&$item) {
@@ -2342,8 +2342,24 @@ function _menu_router_build($callbacks) 
     watchdog('php', 'Menu router rebuild failed - some paths may not work correctly.', array(), WATCHDOG_ERROR);
     return array();
   }
-  // Delete the existing router since we have some data to replace it.
-  db_query('DELETE FROM {menu_router}');
+
+  // Prep for multi-insert
+  $data = array();
+  $chunks = 0;
+  $loop_counter = 0;
+  if (stristr($db_type, 'pgsql')) {
+    // Set Max Packet size to 16MB if using postgreSQL.
+    $max_packet = 16777216;
+  }
+  else {
+    // Get maximum packet size for mysql
+    $max_packet = db_result(db_query("SHOW VARIABLES WHERE Variable_name = 'max_allowed_packet'"));
+    // default to 1/2 MB
+    $max_packet = $max_packet > 524288 ? $max_packet : 524288;
+    // Assume 50 Kb is max size of each insert
+    $max_chunk = $max_packet/51200;
+  }
+
   // Apply inheritance rules.
   foreach ($menu as $path => $v) {
     $item = &$menu[$path];
@@ -2425,22 +2441,83 @@ function _menu_router_build($callbacks) 
     }
 
     $title_arguments = $item['title arguments'] ? serialize($item['title arguments']) : '';
-    db_query("INSERT INTO {menu_router}
-      (path, load_functions, to_arg_functions, access_callback,
-      access_arguments, page_callback, page_arguments, fit,
-      number_parts, tab_parent, tab_root,
-      title, title_callback, title_arguments,
-      type, block_callback, description, position, weight, file)
-      VALUES ('%s', '%s', '%s', '%s',
-      '%s', '%s', '%s', %d,
-      %d, '%s', '%s',
-      '%s', '%s', '%s',
-      %d, '%s', '%s', '%s', %d, '%s')",
-      $path, $item['load_functions'], $item['to_arg_functions'], $item['access callback'],
-      serialize($item['access arguments']), $item['page callback'], serialize($item['page arguments']), $item['_fit'],
-      $item['_number_parts'], $item['tab_parent'], $item['tab_root'],
-      $item['title'], $item['title callback'], $title_arguments,
-      $item['type'], $item['block callback'], $item['description'], $item['position'], $item['weight'], $item['include file']);
+
+    $data[$chunks][] = $path;
+    $data[$chunks][] = $item['load_functions'];
+    $data[$chunks][] = $item['to_arg_functions'];
+    $data[$chunks][] = $item['access callback'];
+    $data[$chunks][] = serialize($item['access arguments']);
+    $data[$chunks][] = $item['page callback'];
+    $data[$chunks][] = serialize($item['page arguments']);
+    $data[$chunks][] = $item['_fit'];
+    $data[$chunks][] = $item['_number_parts'];
+    $data[$chunks][] = $item['tab_parent'];
+    $data[$chunks][] = $item['tab_root'];
+    $data[$chunks][] = $item['title'];
+    $data[$chunks][] = $item['title callback'];
+    $data[$chunks][] = $title_arguments;
+    $data[$chunks][] = $item['type'];
+    $data[$chunks][] = $item['block callback'];
+    $data[$chunks][] = $item['description'];
+    $data[$chunks][] = $item['position'];
+    $data[$chunks][] = $item['weight'];
+    $data[$chunks][] = $item['include file'];
+
+    $loop_counter++;
+    if ($loop_counter > $max_chunk) {
+      $chunks++;
+      $loop_counter = 0;
+    }
+  }
+
+  // Delete the existing router since we have some data to replace it.
+  db_query('DELETE FROM {menu_router}');
+  // Run the multi insert
+  foreach ($data as $values) {
+    _db_insert_multi('menu_router', array(
+      'path',
+      'load_functions',
+      'to_arg_functions',
+      'access_callback',
+      'access_arguments',
+      'page_callback',
+      'page_arguments',
+      'fit',
+      'number_parts',
+      'tab_parent',
+      'tab_root',
+      'title',
+      'title_callback',
+      'title_arguments',
+      'type',
+      'block_callback',
+      'description',
+      'position',
+      'weight',
+      'file',
+      ),
+      array(
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "%d",
+      "%d",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "%d",
+      "'%s'",
+      "'%s'",
+      "'%s'",
+      "%d",
+      "'%s'",
+      ), $values);
   }
   // Sort the masks so they are in order of descending fit, and store them.
   $masks = array_keys($masks);
@@ -2451,6 +2528,50 @@ function _menu_router_build($callbacks) 
 }
 
 /**
+ * Insert many records into the database.
+ *
+ * NOTE Be aware of the MySQL's max_packet_size variable.
+ *
+ * @param $table
+ *   The name of the table.
+ * @param $fields
+ *   array of field names to be updated
+ * @param $placeholders
+ *   array of db_query placeholders; like %d or '%s'
+ * @param $values
+ *   array of values you wish to be inserted. If you have 3 fields then the
+ *   array should be structured like
+ *    array($field_1_value_A, $field_2_value_A, $field_3_value_A,
+ *           $field_1_value_B, $field_2_value_B, $field_3_value_B);
+ * @param $suppress
+ *   bool. TRUE to suppress db_query errors
+ * @return
+ *   returns db_query() result.
+ */
+function _db_insert_multi($table, $fields, $placeholders, $data, $suppress = FALSE) {
+  // Get the number of rows that will be inserted
+  $rows = count($data)/count($fields);
+  // Build the values placeholders string.
+  $values = '(' . implode(', ', $placeholders) . ')';
+  // Create what goes in the IN ()
+  $v = $values;
+  // Add the rest of the place holders
+  for ($i = 1; $i < $rows; $i++) {
+    $v .= ', ' . $values;
+  }
+  // Build the fields part of this query
+  $fields = implode(', ', $fields);
+  $query = "INSERT INTO {" . $table . "} ($fields) VALUES $v";
+  // Run the query
+  if ($suppress) {
+    return @db_query($query, $data);
+  }
+  else {
+    return db_query($query, $data);
+  }
+}
+
+/**
  * Returns TRUE if a path is external (e.g. http://example.com).
  */
 function menu_path_is_external($path) {
