? userlower.patch
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.256
diff -u -p -r1.256 system.install
--- modules/system/system.install	1 Jul 2008 20:36:40 -0000	1.256
+++ modules/system/system.install	8 Jul 2008 13:22:15 -0000
@@ -354,12 +354,12 @@ function system_install() {
   // uid 2 which is not what we want. So we insert the first user here, the
   // anonymous user. uid is 1 here for now, but very soon it will be changed
   // to 0.
-  db_query("INSERT INTO {users} (name, mail) VALUES('%s', '%s')", '', '');
+  db_query("INSERT INTO {users} (name, username, mail) VALUES('%s', '%s', '%s')", '', '', '');
   // We need some placeholders here as name and mail are uniques and data is
   // presumed to be a serialized array. Install will change uid 1 immediately
   // anyways. So we insert the superuser here, the uid is 2 here for now, but
   // very soon it will be changed to 1.
-  db_query("INSERT INTO {users} (name, mail, created, data) VALUES('%s', '%s', %d, '%s')", 'placeholder-for-uid-1', 'placeholder-for-uid-1', time(), serialize(array()));
+  db_query("INSERT INTO {users} (name, username, mail, created, data) VALUES('%s', '%s', '%s', %d, '%s')", 'placeholder-for-uid-1', 'placeholder-for-uid-1', 'placeholder-for-uid-1', time(), serialize(array()));
   // This sets the above two users uid 0 (anonymous). We avoid an explicit 0
   // otherwise MySQL might insert the next auto_increment value.
   db_query("UPDATE {users} SET uid = uid - uid WHERE name = '%s'", '');
Index: modules/user/user.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.install,v
retrieving revision 1.12
diff -u -p -r1.12 user.install
--- modules/user/user.install	7 May 2008 19:34:24 -0000	1.12
+++ modules/user/user.install	8 Jul 2008 13:22:15 -0000
@@ -101,7 +101,14 @@ function user_schema() {
         'length' => 60,
         'not null' => TRUE,
         'default' => '',
-        'description' => t('Unique user name.'),
+        'description' => t('User name for display.'),
+      ),
+      'username' => array(
+        'type' => 'varchar',
+        'length' => 60,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => t('Unique user name for login.'),
       ),
       'pass' => array(
         'type' => 'varchar',
@@ -197,7 +204,7 @@ function user_schema() {
       'mail' => array('mail'),
     ),
     'unique keys' => array(
-      'name' => array('name'),
+      'username' => array('username'),
     ),
     'primary key' => array('uid'),
   );
@@ -292,6 +299,20 @@ function user_update_7001() {
 }
 
 /**
+ * Add username column and populate it with lowercased versions of existing
+ * names.
+ */
+function user_update_7002() {
+  $ret = array();
+  db_add_field($ret, 'users', 'username', array('type' => 'varchar', 'length' => 60, 'not null' => TRUE, 'default' => ''));
+  db_drop_unique_key($ret, 'users', 'name');
+  $ret[] = update_sql("UPDATE {users} SET username = LOWER(name)");
+  db_add_unique_key($ret, 'users', 'username', array('username'));
+
+  return $ret;
+}
+
+/**
  * @} End of "defgroup user-updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.911
diff -u -p -r1.911 user.module
--- modules/user/user.module	27 Jun 2008 07:25:11 -0000	1.911
+++ modules/user/user.module	8 Jul 2008 13:22:15 -0000
@@ -166,6 +166,10 @@ function user_load($array = array()) {
       $query[] = "pass = '%s'";
       $params[] = $value;
     }
+    else if ($key == 'username') {
+      $query[] = "username = LOWER '%s')";
+      $params[] = $value;
+    }
     else {
       $query[]= "LOWER($key) = LOWER('%s')";
       $params[] = $value;
@@ -234,6 +238,11 @@ function user_save($account, $array = ar
     unset($array['pass']);
   }
 
+  // Set the username to a lower case version of $user->name if not set.
+  if (empty($array['username'])) {
+    $array['username'] = drupal_strtolower($array['name']);
+  }
+
   if (is_object($account) && $account->uid) {
     user_module_invoke('update', $array, $account, $category);
     $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
@@ -606,13 +615,13 @@ function user_search($op = 'search', $ke
         $keys = preg_replace('!\*+!', '%', $keys);
         if (user_access('administer users')) {
           // Administrators can also search in the otherwise private email field.
-          $result = pager_query("SELECT name, uid, mail FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%') OR LOWER(mail) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys, $keys);
+          $result = pager_query("SELECT name, uid, mail FROM {users} WHERE username LIKE LOWER('%%%s%%') OR LOWER(mail) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys, $keys);
           while ($account = db_fetch_object($result)) {
             $find[] = array('title' => $account->name . ' (' . $account->mail . ')', 'link' => url('user/' . $account->uid, array('absolute' => TRUE)));
           }
         }
         else {
-          $result = pager_query("SELECT name, uid FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
+          $result = pager_query("SELECT name, uid FROM {users} WHERE name LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
           while ($account = db_fetch_object($result)) {
             $find[] = array('title' => $account->name, 'link' => url('user/' . $account->uid, array('absolute' => TRUE)));
           }
@@ -1514,7 +1523,7 @@ function _user_edit_validate($uid, &$edi
     if ($error = user_validate_name($edit['name'])) {
       form_set_error('name', $error);
     }
-    else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid, $edit['name'])) > 0) {
+    else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND username = LOWER('%s')", $uid, $edit['name'])) > 0) {
       form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name'])));
     }
   }
Index: modules/user/user.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.pages.inc,v
retrieving revision 1.13
diff -u -p -r1.13 user.pages.inc
--- modules/user/user.pages.inc	14 Apr 2008 17:48:43 -0000	1.13
+++ modules/user/user.pages.inc	8 Jul 2008 13:22:16 -0000
@@ -12,7 +12,7 @@
 function user_autocomplete($string = '') {
   $matches = array();
   if ($string) {
-    $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string, 0, 10);
+    $result = db_query_range("SELECT name FROM {users} WHERE username LIKE LOWER('%s%%')", $string, 0, 10);
     while ($user = db_fetch_object($result)) {
       $matches[$user->name] = check_plain($user->name);
     }
Index: modules/user/user.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.test,v
retrieving revision 1.10
diff -u -p -r1.10 user.test
--- modules/user/user.test	27 Jun 2008 07:25:11 -0000	1.10
+++ modules/user/user.test	8 Jul 2008 13:22:16 -0000
@@ -39,7 +39,8 @@ class UserRegistrationTestCase extends D
     $this->assertTrue($user->uid > 0, t('User has valid user id.'));
 
     // Check user fields.
-    $this->assertEqual($user->name, $name, t('Username matches.'));
+    $this->assertEqual($user->name, $name, t('User name matches.'));
+    $this->assertEqual($user->username, drupal_strtolower($name), t('Username matches. '));
     $this->assertEqual($user->mail, $mail, t('E-mail address matches.'));
     $this->assertEqual($user->theme, '', t('Correct theme field.'));
     $this->assertEqual($user->signature, '', t('Correct signature field.'));
