Index: includes/install.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/install.inc,v
retrieving revision 1.31
diff -u -p -r1.31 install.inc
--- includes/install.inc	2 Jan 2007 05:05:38 -0000	1.31
+++ includes/install.inc	25 Jan 2007 07:44:53 -0000
@@ -739,3 +739,28 @@ function drupal_check_module($module) {
   }
   return TRUE;
 }
+
+/**
+ * Add a permission.
+ * This function will add a permission to the permission table and return the pid.
+ * If the permission already exists, its pid will be returned instead.
+ */
+function drupal_add_permission($perm, $module='') {
+  if ($pid = db_result(db_query("SELECT pid FROM {permission} WHERE perm = '%s'",$perm))) {
+    return $pid;
+  }
+  $pid = db_next_id('{permission}_pid');
+  db_query("INSERT INTO {permission} (pid,perm,module) VALUES (%d,'%s','%s')",$pid,$perm,$module);
+  return $pid;
+}
+
+/**
+ * Delete a permission.
+ * This function will permanetly remove a permission.
+ */
+function drupal_del_permission($perm) {
+  if ($pid = db_result(db_query("SELECT pid FROM {permission} WHERE perm = '%s'",$perm))) {
+    db_query("DELETE FROM {permission_role} WHERE pid = %d",$pid);
+    db_query("DELETE FROM {permission} WHERE pid = %d",$pid);
+  }
+}
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.94
diff -u -p -r1.94 module.inc
--- includes/module.inc	24 Jan 2007 14:48:35 -0000	1.94
+++ includes/module.inc	25 Jan 2007 07:44:53 -0000
@@ -253,6 +253,8 @@ function module_enable($module_list) {
     module_list(TRUE, FALSE);
     // Force to regenerate the stored list of hook implementations.
     module_implements('', FALSE, TRUE);
+    // Check for new permissions.
+    user_update_permissions();
   }
 
   foreach ($invoke_modules as $module) {
Index: modules/comment/comment.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.install,v
retrieving revision 1.2
diff -u -p -r1.2 comment.install
--- modules/comment/comment.install	13 Dec 2006 22:44:54 -0000	1.2
+++ modules/comment/comment.install	25 Jan 2007 07:44:53 -0000
@@ -9,3 +9,12 @@ function comment_enable() {
   db_query_temporary("SELECT n.nid, n.created, n.uid FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE c.comment_count IS NULL", 'missing_nids');
   db_query("INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) SELECT n.nid, n.created, NULL, n.uid, 0 FROM missing_nids n");
 }
+
+/**
+ * Implementation of hook_install().
+ */
+function comment_install() {
+  drupal_add_permission('access comments','comment');
+  drupal_add_permission('post comments','comment');
+  drupal_add_permission('post comments without approval','comment');
+}
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.73
diff -u -p -r1.73 system.install
--- modules/system/system.install	24 Jan 2007 14:48:36 -0000	1.73
+++ modules/system/system.install	25 Jan 2007 07:44:53 -0000
@@ -226,6 +226,7 @@ function system_install() {
         PRIMARY KEY (cid),
         INDEX expire (expire)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+
       db_query("CREATE TABLE {cache_filter} (
         cid varchar(255) NOT NULL default '',
         data longblob,
@@ -430,14 +431,21 @@ function system_install() {
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
       db_query("CREATE TABLE {permission} (
-        rid int unsigned NOT NULL default '0',
-        perm longtext,
-        tid int unsigned NOT NULL default '0',
-        KEY rid (rid)
+        pid int(10) unsigned NOT NULL default '0',
+        perm varchar(255) NOT NULL default '',
+        module 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} (
-        rid int unsigned NOT NULL auto_increment,
+        rid int unsigned NOT NULL,
         name varchar(64) NOT NULL default '',
         PRIMARY KEY (rid),
         UNIQUE KEY name (name)
@@ -898,19 +906,26 @@ function system_install() {
       )");
       db_query("CREATE INDEX {url_alias}_src_idx ON {url_alias} (src)");
 
+      db_query("CREATE TABLE {role} (
+        rid int_unsigned NOT NULL default '0',
+        name varchar(64) NOT NULL default '',
+        PRIMARY KEY (rid),
+        UNIQUE (name)
+      )");
+
       db_query("CREATE TABLE {permission} (
         rid int_unsigned NOT NULL default '0',
-        perm text,
-        tid int_unsigned NOT NULL default '0'
+        perm varchar(255) NOT NULL default '',
+        module varchar(255) NOT NULL default '',
       )");
       db_query("CREATE INDEX {permission}_rid_idx ON {permission} (rid)");
+      db_query("CREATE INDEX {permission}_perm_idx ON {permission} (perm)");
 
-      db_query("CREATE TABLE {role} (
-        rid serial CHECK (rid >= 0),
-        name varchar(64) NOT NULL default '',
-        PRIMARY KEY (rid),
-        UNIQUE (name)
+      db_query("CREATE TABLE {permission_role} (
+        pid int_unsigned NOT NULL default '0',
+        rid int_unsigned NOT NULL default '0'
       )");
+      db_query("CREATE INDEX {permission_role}_pid_rid_idx ON {permission_role} (rid, pid)");
 
       db_query("CREATE TABLE {blocks_roles} (
         module varchar(64) NOT NULL,
@@ -1082,11 +1097,14 @@ function system_install() {
 
   db_query("INSERT INTO {users} (uid,name,mail) VALUES(0,'','')");
 
-  db_query("INSERT INTO {role} (name) VALUES ('anonymous user')");
-  db_query("INSERT INTO {role} (name) VALUES ('authenticated user')");
+  db_query("INSERT INTO {role} (rid, name) VALUES (1, 'anonymous user')");
+  db_query("INSERT INTO {role} (rid, name) VALUES (2, 'authenticated user')");
+  db_query("INSERT INTO {sequences} (name, id) VALUES ('{role}_rid', 2)");
+
+  drupal_add_permission('access content','node');
 
-  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)");
+//  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)");
 
   db_query("INSERT INTO {variable} (name,value) VALUES('theme_default', 's:7:\"garland\";')");
 
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.746
diff -u -p -r1.746 user.module
--- modules/user/user.module	24 Jan 2007 14:48:36 -0000	1.746
+++ modules/user/user.module	25 Jan 2007 07:44:54 -0000
@@ -348,33 +348,29 @@ 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;
   }
 
-  // User #1 has all privileges:
+  // User #1 has all privileges.
   if ($account->uid == 1) {
     return TRUE;
   }
 
-  // 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, ";
-    }
+  // Fold user's roles into an SQL fragment.
+  if (!isset($role_string[$account->uid])) {
+    $role_string[$account->uid] = implode(',', array_keys($account->roles));
   }
 
-  if (isset($perm[$account->uid])) {
-    return strpos($perm[$account->uid], "$string, ") !== FALSE;
+  // If we don't have this permission cached yet, get it. 
+  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;
+  // If the permission was set and granted to the role, access is granted.
+  return isset($perm[$account->uid][$string]) && $perm[$account->uid][$string];
 }
 
 /**
@@ -1842,7 +1838,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');
@@ -1859,26 +1855,27 @@ function user_roles($membersonly = 0, $p
  * Menu callback: administer permissions.
  */
 function user_admin_perm($rid = NULL) {
+
+  // Compile permissions map.
+  $status = array();
   if (is_numeric($rid)) {
-    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid = %d', $rid);
+    $result = db_query('SELECT pr.rid, pr.pid FROM {permission_role} pr INNER JOIN {permission} p ON pr.pid = p.pid WHERE pr.rid = %d', $rid);
   }
   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 pr.rid, pr.pid FROM {permission_role} pr INNER JOIN {permission} p ON pr.pid = p.pid');
   }
-
-  // Compile role array:
-  while ($role = db_fetch_object($result)) {
-    $role_permissions[$role->rid] = $role->perm;
+  while ($row = db_fetch_object($result)) {
+    $status[$row->rid][] = $row->pid;
   }
 
+  // Compile role list.
+  $role_names = array();
   if (is_numeric($rid)) {
-    $result = db_query('SELECT rid, name FROM {role} r WHERE r.rid = %d ORDER BY name', $rid);
+    $result = db_query('SELECT rid, name FROM {role} WHERE rid = %d',$rid);
   }
   else {
-    $result = db_query('SELECT rid, name FROM {role} ORDER BY name');
+    $result = db_query('SELECT rid, name FROM {role}');
   }
-
-  $role_names = array();
   while ($role = db_fetch_object($result)) {
     $role_names[$role->rid] = $role->name;
   }
@@ -1887,19 +1884,18 @@ function user_admin_perm($rid = NULL) {
   $options = array();
   foreach (module_list(FALSE, FALSE, TRUE) as $module) {
     if ($permissions = module_invoke($module, 'perm')) {
-      $form['permission'][] = array(
+      $form['permission'][$module] = array(
         '#value' => $module,
       );
       asort($permissions);
       foreach ($permissions as $perm) {
-        $options[$perm] = '';
-        $form['permission'][$perm] = array('#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;
-          }
-        }
+        $result = db_query("SELECT pid FROM {permission} WHERE perm = '%s'",$perm);
+        $pid = db_result($result);
+
+        // Add permission as an option
+        $options[$pid] = '';
+        $form['permission'][$pid] = array('#value' => t($perm));
+        
       }
     }
   }
@@ -1920,7 +1916,7 @@ function theme_user_admin_perm($form) {
     if (is_array($form['permission'][$key])) {
       $row = array();
       // Module name
-      if (is_numeric($key)) {
+      if (!is_numeric($key)) {
         $row[] = array('data' => t('@module module', array('@module' => drupal_render($form['permission'][$key]))), 'class' => 'module', 'id' => 'module-'. $form['permission'][$key]['#value'], 'colspan' => count($form['role_names']) + 1);
       }
       else {
@@ -1952,10 +1948,10 @@ function user_admin_perm_submit($form_id
     if (isset($form_values[$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);
+      db_query('DELETE FROM {permission_role} WHERE rid = %d',$role->rid);
       $form_values[$role->rid] = array_filter($form_values[$role->rid]);
-      if (count($form_values[$role->rid])) {
-        db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($form_values[$role->rid])));
+      foreach ($form_values[$role->rid] AS $perm => $pid) {
+        db_query('INSERT INTO {permission_role} (pid, rid) VALUES (%d, %d)',$pid,$role->rid);
       }
     }
   }
@@ -2039,10 +2035,10 @@ function user_admin_role_submit($form_id
     drupal_set_message(t('The role has been renamed.'));
   }
   else if ($form_values['op'] == t('Delete role')) {
-    db_query('DELETE FROM {role} WHERE rid = %d', $form_values['rid']);
-    db_query('DELETE FROM {permission} WHERE rid = %d', $form_values['rid']);
+    db_query('DELETE FROM {permission_role} WHERE rid = %d',$form_values['rid']);
     // Update the users who have this role set:
     db_query('DELETE FROM {users_roles} WHERE rid = %d', $form_values['rid']);
+    db_query('DELETE FROM {role} WHERE rid = %d', $form_values['rid']);
 
     drupal_set_message(t('The role has been deleted.'));
   }
@@ -2737,3 +2733,15 @@ function user_forms() {
   return $forms;
 }
 
+/**
+ * Pick up any new permissions that modules are advertising.
+ */
+function user_update_permissions() {
+  foreach (module_implements('perm') as $module) {
+    foreach (module_invoke($module, 'perm') as $permission) {
+      if (!db_result(db_query("SELECT COUNT(*) FROM {permission} WHERE perm = '%s'", $permission))) {
+        db_query("INSERT INTO {permission} (pid,perm,module) VALUES (%d,'%s','%s')",db_next_id('{permission}_pid'), $permission, $module);
+      }
+    }
+  }
+}

