diff -urpN drupal-6.x-dev-200708201800/includes/bootstrap.inc drupal-6.x-dev-access-0.2/includes/bootstrap.inc
--- drupal-6.x-dev-200708201800/includes/bootstrap.inc	2007-08-07 16:41:24.000000000 +0800
+++ drupal-6.x-dev-access-0.2/includes/bootstrap.inc	2007-08-22 01:12:50.000000000 +0800
@@ -792,11 +792,51 @@ function drupal_get_messages($type = NUL
 }
 
 /**
+ * Initialize the access strategy.
+ */
+function _drupal_access_init() {
+  // NOTE: caching the access rules can greatly improve performance.
+  $accesses = array();
+  if ($cached = cache_get('accesses', 'cache')) {
+    $accesses = $cached->data;
+  }
+  else {
+    $result = db_query('SELECT * FROM {access}');
+
+    // Classify, group and preprocess fetched access rules.
+    $array = array();
+    while ($rule = db_fetch_object($result)) {
+      // Phase is not starting with '^': a plain text format. Escape it 
+      // with preg_quote().
+      if (substr($rule->mask, 0, 1) != '^') {
+        $array[$rule->type][$rule->status ? 'allow' : 'deny'][] = '^' . preg_quote($rule->mask) . '$';
+      }
+      // Phase is starting with '^': a regex expression. No further more
+      // processing.
+      else {
+        $array[$rule->type][$rule->status ? 'allow' : 'deny'][] = $rule->mask;
+      }
+    }
+
+    // Build regex expression for caching.
+    foreach ($array as $type => $tmp) {
+      foreach ($tmp as $status => $mask) {
+        $accesses[$type][$status] = '/' . implode('|', $mask) . '/Ds';
+      }
+    }
+
+    cache_set('accesses', $accesses);
+  }
+
+  return $accesses;
+}
+
+/**
  * Perform an access check for a given mask and rule type. Rules are usually
  * created via admin/user/rules page.
  *
- * If any allow rule matches, access is allowed. Otherwise, if any deny rule
- * matches, access is denied.  If no rule matches, access is allowed.
+ * If any deny rule matches, access is denied. By the way, if any allow rule
+ * matches, access is allowed. If no rule matches, access is allowed.
  *
  * @param $type string
  *   Type of access to check: Allowed values are:
@@ -804,25 +844,27 @@ function drupal_get_messages($type = NUL
  *     - 'mail': e-mail address
  *     - 'user': username
  * @param $mask string
- *   String or mask to test: '_' matches any character, '%' matches any
- *   number of characters.
+ *   String to test.
  * @return bool
  *   TRUE if access is denied, FALSE if access is allowed.
  */
 function drupal_is_denied($type, $mask) {
-  // Because this function is called for every page request, both cached
-  // and non-cached pages, we tried to optimize it as much as possible.
-  // We deny access if the only matching records in the {access} table have
-  // status 0. If any have status 1, or if there are no matching records,
-  // we allow access. So, select matching records in decreasing order of
-  // 'status', returning NOT(status) for the first. If any have status 1,
-  // they come first, and we return NOT(status) = 0 (allowed). Otherwise,
-  // if we have some with status 0, we return 1 (denied). If no matching
-  // records, we get no return from db_result, so we return (bool)NULL = 0
-  // (allowed).
-  // The use of ORDER BY / LIMIT is more efficient than "MAX(status) = 0"
-  // in PostgreSQL <= 8.0.
-  return (bool) db_result(db_query_range("SELECT CASE WHEN status=1 THEN 0 ELSE 1 END FROM {access} WHERE type = '%s' AND LOWER(mask) LIKE LOWER('%s') ORDER BY status DESC", $type, $mask, 0, 1));
+  global $access;
+
+  // First of all, assume access is allowed.
+  $ret = FALSE;
+
+  // Check if deny rules exists. If so, deny access if rule matches.
+  if (isset($access[$type]['deny']) && $access[$type]['deny'] && preg_match($access[$type]['deny'], $mask)) {
+    $ret = TRUE;
+  }
+
+  // Check if allow rules exists. If so, allow access if rule matches.
+  if (isset($access[$type]['allow']) && $access[$type]['allow'] && preg_match($access[$type]['allow'], $mask)) {
+    $ret = FALSE;
+  }
+
+  return $ret;
 }
 
 /**
@@ -878,7 +920,7 @@ function drupal_bootstrap($phase) {
 }
 
 function _drupal_bootstrap($phase) {
-  global $conf;
+  global $conf, $access;
 
   switch ($phase) {
 
@@ -899,6 +941,9 @@ function _drupal_bootstrap($phase) {
       break;
 
     case DRUPAL_BOOTSTRAP_ACCESS:
+      // Initialize the access strategy.
+      $access = _drupal_access_init();
+
       // Deny access to hosts which were banned - t() is not yet available.
       if (drupal_is_denied('host', ip_address())) {
         header('HTTP/1.1 403 Forbidden');
diff -urpN drupal-6.x-dev-200708201800/modules/user/user.module drupal-6.x-dev-access-0.2/modules/user/user.module
--- drupal-6.x-dev-200708201800/modules/user/user.module	2007-08-19 16:08:45.000000000 +0800
+++ drupal-6.x-dev-access-0.2/modules/user/user.module	2007-08-22 01:14:25.000000000 +0800
@@ -2015,6 +2015,7 @@ function user_admin_access_add($mask = N
     $edit['mask'] = $mask;
     $edit['type'] = $type;
   }
+  cache_clear_all('accesses', 'cache');
   return drupal_get_form('user_admin_access_add_form', $edit, t('Add rule'));
 }
 
@@ -2040,6 +2041,7 @@ function user_admin_access_delete_confir
   db_query('DELETE FROM {access} WHERE aid = %d', $form_state['values']['aid']);
   drupal_set_message(t('The access rule has been deleted.'));
   $form_state['redirect'] = 'admin/user/rules';
+  cache_clear_all('accesses', 'cache');
   return;
 }
 
@@ -2060,6 +2062,7 @@ function user_admin_access_edit($aid = 0
   else {
     $edit = db_fetch_array(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
   }
+  cache_clear_all('accesses', 'cache');
   return drupal_get_form('user_admin_access_edit_form', $edit, t('Save rule'));
 }
 
@@ -2083,7 +2086,7 @@ function user_admin_access_form(&$form_s
     '#size' => 30,
     '#maxlength' => 64,
     '#default_value' => $edit['mask'],
-    '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.<br />_: '. t('Matches exactly one character.'),
+    '#description' => t('Start the line with a ^ character to designate a regular expression match.'),
     '#required' => TRUE,
   );
   $form['submit'] = array('#type' => 'submit', '#value' => $submit);
