Index: privatemsg.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg.install,v
retrieving revision 1.5.2.4.2.11.2.11.2.12
diff -u -p -r1.5.2.4.2.11.2.11.2.12 privatemsg.install
--- privatemsg.install	21 Oct 2010 09:12:37 -0000	1.5.2.4.2.11.2.11.2.12
+++ privatemsg.install	11 Dec 2010 17:03:36 -0000
@@ -133,6 +133,9 @@ function privatemsg_schema() {
   return $schema;
 }
 
+/**
+ * Implements hook_uninstall().
+ */
 function privatemsg_uninstall() {
   variable_del('private_message_view_template');
   variable_del('privatemsg_per_page');
@@ -150,6 +153,15 @@ function privatemsg_uninstall() {
 }
 
 /**
+ * Implements hook_update_dependencies().
+ */
+function privatemsg_update_dependencies() {
+  $dependencies['privatemsg']['7004']['privatemsg_filter'] = '7001';
+  return $dependencies;
+}
+
+
+/**
  * Add has_tokens field to indicate if a message is using tokens.
  */
 function privatemsg_update_7000() {
@@ -174,3 +186,126 @@ function privatemsg_update_7001() {
     'description'   => 'The {filter_formats}.format of the message text.',
   ));
 }
+
+
+/**
+ * Add {pm_disable} table.
+ */
+function privatemsg_update_7002() {
+
+  // Make sure to not run this update twice.
+  if (db_table_exists('pm_disable')) {
+    return $ret;
+  }
+
+  $schema['pm_disable'] = array(
+    'description'       => '{pm_disable} holds the list of users that have disabled private messaging',
+    'fields' => array(
+      'uid'    => array(
+        'description'   => 'ID of the user',
+        'type'          => 'int',
+        'not null'      => TRUE,
+        'unsigned'      => TRUE,
+      ),
+    ),
+    'primary key'       => array('uid'),
+  );
+
+  if (!(db_table_exists('pm_disable'))) {
+    db_create_table('pm_disable', $schema['pm_disable']);
+  }
+}
+
+/**
+ * Change schema to allow other recipients than single users.
+ */
+function privatemsg_update_7003() {
+  // Make sure to not run this update twice.
+  if (db_field_exists('pm_index', 'recipient')) {
+    return;
+  }
+  db_drop_index('pm_index', 'uid');
+  db_drop_index('pm_index', 'is_new');
+  db_change_field('pm_index', 'uid', 'recipient', array(
+    'description'   => 'ID of the recipient object, typically user',
+    'type'          => 'int',
+    'not null'      => TRUE,
+    'unsigned'      => TRUE,
+  ));
+  db_add_field('pm_index', 'type', array(
+    'description'   => 'Type of recipient object',
+    'type' => 'varchar',
+    'not null' => TRUE,
+    'length'  => '255',
+    'default' => 'user',
+  ), array(
+    'indexes' => array(
+      'recipient'         => array('recipient', 'type'),
+      'is_new'            => array('mid', 'recipient', 'type', 'is_new'),
+    ),
+  ));
+}
+
+/**
+ * Remove duplicate entries in {pm_index}.
+ */
+function privatemsg_update_7004(&$sandbox) {
+  // If the primary key already exists, this doesn't need to run.
+  if (db_index_exists('pm_index', 'PRIMARY')) {
+    return;
+  }
+
+  // First run, initialize sandbox and check if we are ready to run.
+  if (!isset($sandbox['current_thread_id'])) {
+    $sandbox['current_thread_id'] = 0;
+    // Assume that the thread ids are distributed more or less equally over the
+    // whole data set. This allows us to calculate the approximate progress.
+    $sandbox['max'] = db_query('SELECT MAX(thread_id) FROM {pm_index}')->fetchField();
+  }
+
+  // Fetch the next 10 thread_ids.
+  $result = db_query_range('SELECT DISTINCT thread_id FROM {pm_index} WHERE thread_id > :thread_id ORDER BY thread_id ASC', 0, 20, array(':thread_id' => $sandbox['current_thread_id']));
+  $threads = $result->fetchCol();
+
+  if (!empty($threads)) {
+    // By limiting this slow query (having condition) on a specific set of
+    // threads, this allows us to process the slow having part on a relatively
+    // small subset of pm_index that can be selected based on the thread_id
+    // index. There might also be cases where is_new and/or deleted are not
+    // equal, use MAX(is_new) and MIN(deleted) for these cases.
+    $sql = 'SELECT COUNT(*) AS count, pmi.recipient, pmi.type, pmi.mid, pmi.thread_id, MAX(pmi.is_new) As is_new, MIN(pmi.deleted) AS deleted FROM {pm_index} pmi WHERE thread_id IN (:threads) GROUP BY pmi.recipient, pmi.type, pmi.mid, pmi.thread_id HAVING COUNT(*) > 1';
+    $result = db_query($sql, array(':threads' => $threads));
+    foreach ($result as $row) {
+      // Delete all occurences of these entries.
+      db_delete('pm_index')
+        ->condition('mid', $row->mid)
+        ->condition('recipient', $row->recipient)
+        ->condition('type', $row->type)
+        ->execute();
+      // Re-insert a single entry. We do this to explicitely keep messages
+      // unread and undeleted if there are conflicting entries.
+      db_insert('pm_index')
+        ->fields(array(
+          'mid' => $row->mid,
+          'thread_id' => $row->thread_id,
+          'recipient' => $row->recipient,
+          'type' => $row->type,
+          'is_new' => $row->is_new,
+          'deleted' => $row->deleted,
+        ))
+        ->execute();
+    }
+    $sandbox['current_thread_id'] = max($threads);
+  }
+  // Set #finished based on sandbox.
+  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current_thread_id'] / $sandbox['max']);
+}
+
+/**
+ * Add primary key to {pm_index}.
+ */
+function privatemsg_update_7005() {
+  if (!db_index_exists('pm_index', 'PRIMARY')) {
+    db_add_primary_key('pm_index', array('mid', 'recipient', 'type'));
+  }
+}
Index: privatemsg_filter/privatemsg_filter.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.install,v
retrieving revision 1.1.2.3.2.4
diff -u -p -r1.1.2.3.2.4 privatemsg_filter.install
--- privatemsg_filter/privatemsg_filter.install	17 Mar 2010 23:51:08 -0000	1.1.2.3.2.4
+++ privatemsg_filter/privatemsg_filter.install	11 Dec 2010 17:03:37 -0000
@@ -100,4 +100,81 @@ function privatemsg_filter_enable() {
     variable_set('privatemsg_filter_inbox_tag', $tag_id);
   }
   drupal_set_message(t('Visit <a href="!rebuild_url">Rebuild Inbox</a> to tag existing messages to show up in the inbox.', array('!rebuild_url' => url('admin/config/messaging/privatemsg/tags/rebuild'))));
-}
\ No newline at end of file
+}
+
+
+/**
+ * Add hidden flag and create inbox tag.
+ */
+function privatemsg_filter_update_7000() {
+  if (!db_field_exists('pm_tags', 'hidden')) {
+    db_add_field('pm_tags', 'hidden', array(
+      'description'   => 'Defines if a tag should not be displayed and is usually automatically managed',
+      'type'          => 'int',
+      'unsigned'      => TRUE,
+      'size'          => 'tiny',
+      'default'       => 0,
+    ));
+  }
+
+  if (!($tag_id = variable_get('privatemsg_filter_inbox_tag', '')) || (!db_query('SELECT 1 FROM {pm_tags} WHERE tag_id = :tag_id', array(':tag_id' => $tag_id))->fetchField())) {
+    $tag_id = db_insert('pm_tags')
+      ->fields(array(
+        'tag' => 'Inbox',
+        'hidden' => 1,
+      ))
+      ->execute();
+    variable_set('privatemsg_filter_inbox_tag', $tag_id);
+  }
+}
+
+/**
+ * Add inbox tag to existing inbox messages.
+ */
+function privatemsg_filter_update_7001(&$sandbox) {
+  // First run, initialize sandbox.
+  if (!isset($sandbox['current_thread_id'])) {
+    // If the sandbox is not initialized, check if there are any threads tagged
+    // with the inbox tag. If yes, the update did already run.
+    if (db_query_range('SELECT 1 FROM {pm_tags_index} WHERE tag_id = :tag_id', 0, 1, array(':tag_id' => variable_get('privatemsg_filter_inbox_tag', 0)))->fetchField()) {
+      return;
+    }
+
+    $sandbox['current_thread_id'] = 0;
+    // Assume that the thread ids are distributed more or less equally over the
+    // whole data set. This allows us to calculate the approximate progress.
+    $sandbox['max'] = db_query('SELECT MAX(thread_id) FROM {pm_index}')->fetchField();
+  }
+
+  // Fetch the 10 next thread_ids.
+  $result = db_query_range('SELECT DISTINCT thread_id FROM {pm_index} WHERE thread_id > :thread_id ORDER BY thread_id ASC', 0, 20, array('thread_id' => $sandbox['current_thread_id']));
+  $threads = $result->fetchCol();
+  $inbox_tag = variable_get('privatemsg_filter_inbox_tag', '');
+  if (!empty($threads)) {
+    // By limiting this slow query (having condition with 2 depending subqueries)
+    // on a specific set of threads, this allows us to process the slow having
+    // part on a relatively small subset of pm_index that can be selected based on
+    // the thread_id index.
+    $sql = 'SELECT pmi.thread_id, pmi.uid FROM {pm_index} pmi WHERE thread_id IN (:threads)  GROUP BY pmi.thread_id, pmi.uid HAVING ((SELECT pmf.author FROM pm_message pmf WHERE pmf.mid = pmi.thread_id) = pmi.uid AND COUNT(pmi.thread_id) > 1) OR (SELECT COUNT(*) FROM pm_message pmf INNER JOIN pm_index pmif ON (pmf.mid = pmif.mid) WHERE pmif.thread_id = pmi.thread_id AND pmf.author <> pmi.uid) > 0';
+    $result = db_query($sql, array(':threads' => $threads));
+    foreach ($result as $row) {
+      // Make sure that we don't add a tag to a thread twice,
+      // only insert if there is no such tag yet.
+      // We duplicate privatemsg_filter_add_tags() here in case
+      // privatemsg_filter.module is disabled and therefore not loaded.
+      $exists = db_query('SELECT 1 FROM {pm_tags_index} WHERE tag_id = :tag_id AND (uid = :uid AND thread_id = :thread_id)', array(':tag_id' => $inbox_tag, ':uid' => $row->uid, ':thread_id' => $row->thread_id))->fetchField();
+      if (!$exists) {
+        db_insert('pm_tags_index')
+          ->fields(array(
+            'tag_id' => $inbox_tag,
+            'uid' => $row->uid,
+            'thread_id' => $row->thread_id,
+          ))
+          ->execute();
+      }
+    }
+    $sandbox['current_thread_id'] = max($threads);
+  }
+  // Set #finished based on sandbox.
+  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current_thread_id'] / $sandbox['max']);
+}
