=== modified file 'modules/system/system.install'
--- modules/system/system.install	
+++ modules/system/system.install	
@@ -208,10 +208,16 @@ function system_install() {
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
       db_query("CREATE TABLE {permission} (
-        rid int(10) unsigned NOT NULL default '0',
-        perm longtext,
-        tid int(10) unsigned NOT NULL default '0',
-        KEY rid (rid)
+        pid int(10) unsigned NOT NULL default '0',
+        perm varchar(255) NOT NULL default '',
+        PRIMARY KEY  (pid),
+        UNIQUE KEY perm (perm)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+
+      db_query("CREATE TABLE {permission_role} (
+        pid int(10) unsigned NOT NULL,
+        rid int(10) unsigned NOT NULL,
+        PRIMARY KEY  (pid,rid)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
       db_query("CREATE TABLE {role} (
@@ -395,8 +401,12 @@ function system_install() {
   db_query("INSERT INTO {role} (name) VALUES ('anonymous user')");
   db_query("INSERT INTO {role} (name) VALUES ('authenticated user')");
 
-  db_query("INSERT INTO {permission} VALUES (1,'access content',0)");
-  db_query("INSERT INTO {permission} VALUES (2,'access comments, access content, post comments, post comments without approval',0)");
+  foreach (array(1 => 'access comments', 'access content', 'post comments', 'post comments without approval') as $pid => $perm) {
+    db_query("INSERT INTO {permission} VALUES (%d, '%s')", $pid, $perm);
+    db_query("INSERT INTO {permission_role} (rid, pid) VALUES (2, %d), $pid");
+  }
+  db_query("INSERT INTO {permission_role} (rid, pid) VALUES (1, 2)");
+  db_query("INSERT INTO {sequences} (name, value) VALUES ('{permission}_pid', 4)");
 
   db_query("INSERT INTO {variable} (name,value) VALUES('theme_default', 's:10:\"bluemarine\";')");
 
=== modified file 'modules/user/user.module'
--- modules/user/user.module	
+++ modules/user/user.module	
@@ -340,7 +340,7 @@ function user_password($length = 10) {
  */
 function user_access($string, $account = NULL) {
   global $user;
-  static $perm = array();
+  static $perm = array(), $role_string = array();
 
   if (is_null($account)) {
     $account = $user;
@@ -350,23 +350,17 @@ function user_access($string, $account =
   if ($account->uid == 1) {
     return TRUE;
   }
+  if (!isset($role_string[$account->uid])) {
+    $role_string[$account->uid] = implode(',', array_keys($account->roles));
+  }
 
   // To reduce the number of SQL queries, we cache the user's permissions
   // in a static variable.
-  if (!isset($perm[$account->uid])) {
-    $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', array_keys($account->roles)));
-
-    $perm[$account->uid] = '';
-    while ($row = db_fetch_object($result)) {
-      $perm[$account->uid] .= "$row->perm, ";
-    }
-  }
-
-  if (isset($perm[$account->uid])) {
-    return strpos($perm[$account->uid], "$string, ") !== FALSE;
+  if (!isset($perm[$account->uid][$string])) {
+    $perm[$account->uid][$string] = db_num_rows(db_query_range("SELECT p.pid FROM {permission_role} pr INNER JOIN {permission} p ON pr.pid = p.pid WHERE perm = '%s' AND rid IN (%s)", $string, $role_string[$account->uid], 0, 1));
   }
 
-  return FALSE;
+  return isset($perm[$account->uid][$string]) && $perm[$account->uid][$string];
 }
 
 /**
@@ -1679,7 +1673,7 @@ function user_roles($membersonly = 0, $p
   $roles = array();
 
   if ($permission) {
-    $result = db_query("SELECT r.* FROM {role} r INNER JOIN {permission} p ON r.rid = p.rid WHERE p.perm LIKE '%%%s%%' ORDER BY r.name", $permission);
+    $result = db_query("SELECT r.* FROM {role} r INNER JOIN {permission_role} pr ON r.rid = pr.rid INNER JOIN {permission} p ON pr.pid = p.pid WHERE p.perm = '%s' ORDER BY r.name", $permission);
   }
   else {
     $result = db_query('SELECT * FROM {role} ORDER BY name');
@@ -1701,23 +1695,24 @@ function user_admin_perm($str_rids = NUL
     $rids = preg_split('/[+ ]/', $str_rids);
   }
 
-  if($rids) {
+  if ($rids) {
     $breadcrumbs = drupal_get_breadcrumb();
     $breadcrumbs[] = l(t('all roles'), 'admin/access');
     drupal_set_breadcrumb($breadcrumbs);
-    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid IN (%s) ORDER BY name', implode(', ', $rids));
+    $result = db_query('SELECT * FROM {permission_role} WHERE rid IN (%s)', implode(', ', $rids));
   }
   else {
-    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
+    $result = db_query('SELECT * FROM {permission_role}');
   }
 
-  // Compile role array:
+  // Builds arrays for checked boxes for each role
   $roles = array();
   while ($role = db_fetch_object($result)) {
-    $role_permissions[$role->rid] = $role->perm;
+    $status[$role->rid][] = $role->pid;
   }
 
-  if($rids) {
+  // Compile role array:
+  if ($rids) {
     $result = db_query('SELECT rid, name FROM {role} r WHERE r.rid IN (%s) ORDER BY name', implode(', ', $rids));
   }
   else {
@@ -1728,24 +1723,40 @@ function user_admin_perm($str_rids = NUL
     $role_names[$role->rid] = $role->name;
   }
 
+  $stored_permissions = array();
+  $result = db_query('SELECT pid, perm FROM {permission} ORDER BY perm ASC');
+  while ($permission = db_fetch_object($result)) {
+    $stored_permissions[$permission->perm] = $permission->pid;
+  }
+  $new_permissions = array();
+
   // Render role/permission overview:
   $options = array();
   foreach (module_list(FALSE, FALSE, TRUE) as $module) {
     if ($permissions = module_invoke($module, 'perm')) {
-      $form['permission'][] = array('#type' => 'markup', '#value' => t('%module module', array('%module' => $module)));
+      $form['permission'][$module] = array('#type' => 'markup', '#value' => t('%module module', array('%module' => $module)));
       asort($permissions);
       foreach ($permissions as $perm) {
-        $options[$perm] = '';
-        $form['permission'][$perm] = array('#type' => 'markup', '#value' => t($perm));
-        foreach ($role_names as $rid => $name) {
-          // Builds arrays for checked boxes for each role
-          if (strstr($role_permissions[$rid], $perm)) {
-            $status[$rid][] = $perm;
-          }
+        if (!isset($stored_permissions[$perm])) {
+          $pid = db_next_id('{permission}_pid');
+        }
+        else {
+          $pid = $stored_permissions[$perm];
         }
+        $new_permissions[$perm] = $pid;
+        $options[$pid] = '';
+        $form['permission'][$pid] = array('#type' => 'markup', '#value' => t($perm));
       }
     }
   }
+  ksort($new_permissions);
+  if (array_keys($stored_permissions) != array_keys($new_permissions)) {
+    db_query('DELETE FROM {permission}');
+    foreach($new_permissions as $perm => $pid) {
+      db_query("INSERT INTO {permission} (pid, perm) VALUES (%d, '%s')", $pid, $perm);
+    }
+  }
+
   // Have to build checkboxes here after checkbox arrays are built
   foreach ($role_names as $rid => $name) {
     $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status[$rid]);
@@ -1761,12 +1772,8 @@ function theme_user_admin_perm($form) {
     // Don't take form control structures
     if (is_array($form['permission'][$key])) {
       $row = array();
-      // Module name
-      if (is_numeric($key)) {
-        $row[] = array('data' => form_render($form['permission'][$key]), 'class' => 'module', 'colspan' => count($form['role_names']) + 1);
       // Permissions
-      }
-      else {
+      if (is_numeric($key)) {
         $row[] = array('data' => form_render($form['permission'][$key]), 'class' => 'permission');
         foreach (element_children($form['checkboxes']) as $rid) {
           if (is_array($form['checkboxes'][$rid])) {
@@ -1774,6 +1781,10 @@ function theme_user_admin_perm($form) {
           }
         }
       }
+      // Module name
+      else {
+        $row[] = array('data' => form_render($form['permission'][$key]), 'class' => 'module', 'colspan' => count($form['role_names']) + 1);
+      }
       $rows[] = $row;
     }
   }
@@ -1792,17 +1803,12 @@ function user_admin_perm_submit($form_id
   // Save permissions:
   $result = db_query('SELECT * FROM {role}');
   while ($role = db_fetch_object($result)) {
-    if(isset($edit[$role->rid])) {
+    if (isset($edit[$role->rid])) {
       // Delete, so if we clear every checkbox we reset that role;
       // otherwise permissions are active and denied everywhere.
-      db_query('DELETE FROM {permission} WHERE rid = %d', $role->rid);
-      foreach ($edit[$role->rid] as $key => $value) {
-        if (!$value) {
-          unset($edit[$role->rid][$key]);
-        }
-      }
-      if (count($edit[$role->rid])) {
-        db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($edit[$role->rid])));
+      db_query('DELETE FROM {permission_role} WHERE rid = %d', $role->rid);
+      foreach (array_keys(array_filter($edit[$role->rid])) as $pid) {
+        db_query("INSERT INTO {permission_role} (rid, pid) VALUES (%d, '%s')", $role->rid, $pid);
       }
     }
   }
@@ -1834,19 +1840,8 @@ function user_admin_role() {
   }
   else if ($op == t('Delete role')) {
     db_query('DELETE FROM {role} WHERE rid = %d', $id);
-    db_query('DELETE FROM {permission} WHERE rid = %d', $id);
-
-    // Update the users who have this role set:
-    $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
-    $uid = array();
-
-    while ($u = db_fetch_object($result)) {
-      $uid[] = $u->uid;
-    }
-
-    if ($uid) {
-      db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
-    }
+    db_query('DELETE FROM {permission_role} WHERE rid = %d', $id);
+    db_query('DELETE FROM {users_roles} WHERE rid = %d', $id);
 
     drupal_set_message(t('The role has been deleted.'));
     drupal_goto('admin/access/roles');
