Index: privatemsg.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v retrieving revision 1.70.2.30.2.91.2.93 diff -u -p -r1.70.2.30.2.91.2.93 privatemsg.module --- privatemsg.module 10 Nov 2009 19:48:17 -0000 1.70.2.30.2.91.2.93 +++ privatemsg.module 10 Nov 2009 20:43:51 -0000 @@ -1000,21 +1000,28 @@ function pm_preview($form, &$form_state) function privatemsg_sql_list(&$fragments, $account, $argument = 'list') { $fragments['primary_table'] = '{pm_message} pm'; - // Load enabled columns + // Load enabled columns. $fields = array_filter(variable_get('privatemsg_display_fields', array('participants'))); - // Required columns + // Required columns. $fragments['select'][] = 'pmi.thread_id'; + // We have to use MIN as the subject might not be the same in some threads. + // MIN() does not have a useful meaning except that it helps to correctly + // aggregate the thread on PostgreSQL. $fragments['select'][] = 'MIN(pm.subject) as subject'; $fragments['select'][] = 'MAX(pm.timestamp) as last_updated'; + // We use SUM so that we can count the number of unread messages. $fragments['select'][] = 'SUM(pmi.is_new) as is_new'; + // Select number of messages in the thread if enabled. if (in_array('count', $fields)) { - $fragments['select'][] = 'COUNT(distinct pmi.mid) as count'; // We only want the distinct number of messages in this thread. + $fragments['select'][] = 'COUNT(distinct pmi.mid) as count'; } if (in_array('participants', $fields)) { - // Query for a string with uid's, for example "1,6,7". This needs a subquery on PostgreSQL. + // Query for a string with uid's, for example "1,6,7". + // @todo: Replace this with a single query similiar to the tag list. if ($GLOBALS['db_type'] == 'pgsql') { + // PostgreSQL does not know GROUP_CONCAT, so a subquery is required. $fragments['select'][] = "array_to_string(array(SELECT DISTINCT textin(int4out(pmia.uid)) FROM {pm_index} pmia WHERE pmia.thread_id = pmi.thread_id), ',') AS participants"; @@ -1028,8 +1035,10 @@ function privatemsg_sql_list(&$fragments if (in_array('thread_started', $fields)) { $fragments['select'][] = 'MIN(pm.timestamp) as thread_started'; } - // pm_index needs to be the first join. + $fragments['inner_join'][] = 'INNER JOIN {pm_index} pmi ON pm.mid = pmi.mid'; + + // Only load undeleted messages of the current user and group by thread. $fragments['where'][] = 'pmi.uid = %d'; $fragments['query_args']['where'][] = $account->uid; $fragments['where'][] = 'pmi.deleted = 0'; @@ -1053,7 +1062,7 @@ function privatemsg_sql_list(&$fragments * Account for which the messages should be loaded. */ function privatemsg_sql_load(&$fragments, $pmids, $account = NULL) { - $fragments['primary_table'] = '{pm_message} pm'; // Our primary table + $fragments['primary_table'] = '{pm_message} pm'; $fragments['select'][] = "pm.mid"; $fragments['select'][] = "pm.author"; @@ -1065,6 +1074,7 @@ function privatemsg_sql_load(&$fragments $fragments['select'][] = "pmi.thread_id"; $fragments['inner_join'][] = 'INNER JOIN {pm_index} pmi ON pm.mid = pmi.mid'; + // Use IN() to load multiple messages at the same time. $fragments['where'][] = 'pmi.mid IN (' . db_placeholders($pmids) . ')'; $fragments['query_args']['where'] += $pmids; if ($account) { @@ -1088,6 +1098,8 @@ function privatemsg_sql_load(&$fragments function privatemsg_sql_messages(&$fragments, $threads, $account = NULL, $load_all = FALSE) { $fragments['primary_table'] = '{pm_index} pmi'; + // Use DISTINCT to only load each mid once even if the user is listed more + // than once as recipient. $fragments['select'][] = 'DISTINCT(pmi.mid) as mid'; $fragments['where'][] = 'pmi.thread_id IN ('. db_placeholders($threads) .')'; $fragments['query_args']['where'] += $threads; @@ -1097,6 +1109,7 @@ function privatemsg_sql_messages(&$fragm $fragments['query_args']['where'][] = $account->uid; } if (!$load_all) { + // Also load deleted messages when requested. $fragments['where'][] = 'pmi.deleted = 0'; } $fragments['order_by'][] = 'pmi.mid ASC'; @@ -1113,6 +1126,8 @@ function privatemsg_sql_messages(&$fragm function privatemsg_sql_participants(&$fragments, $thread_id) { $fragments['primary_table'] = '{pm_index} pmi'; + // Only load each participant once since they are listed as recipient for + // every message of that thread. $fragments['select'][] = 'DISTINCT(pmi.uid) AS uid'; $fragments['select'][] = 'u.name AS name'; @@ -1121,26 +1136,48 @@ function privatemsg_sql_participants(&$f $fragments['query_args']['where'][] = $thread_id; } - +/** + * Query definition to count unread messages. + * + * @param $fragments + * Query fragments array. + * @param $account + * User object for which the messages are being counted. + */ function privatemsg_sql_unread_count(&$fragments, $account) { $fragments['primary_table'] = '{pm_index} pmi'; $fragments['select'][] = 'COUNT(DISTINCT thread_id) as unread_count'; + + // Only count new *and* undeleted messages of that user. $fragments['where'][] = 'pmi.deleted = 0'; $fragments['where'][] = 'pmi.is_new = 1'; $fragments['where'][] = 'pmi.uid = %d'; $fragments['query_args']['where'][] = $account->uid; } +/** + * Query definition to search for username autocomplete suggestions. + * + * @param $fragments + * Query fragments array. + * @param $search + * Which search string is currently searched for. + * @param $names + * Which names are already part of the existing search string and should be excluded. + */ function privatemsg_sql_autocomplete(&$fragments, $search, $names) { $fragments['primary_table'] = '{users} u'; $fragments['select'][] = 'u.name'; + // Escape the % to get it through the placeholder replacement. $fragments['where'][] = "u.name LIKE '%s'"; $fragments['query_args']['where'][] = $search .'%%'; if (!empty($names)) { + // If there are already names selected, exclude them from the suggestions. $fragments['where'][] = "u.name NOT IN (". db_placeholders($names, 'text') .")"; $fragments['query_args']['where'] += $names; } + // Only load active users and sort them by name. $fragments['where'][] = 'u.status <> 0'; $fragments['order_by'][] = 'u.name ASC'; } @@ -1157,14 +1194,19 @@ function privatemsg_sql_deleted(&$fragme $fragments['primary_table'] = '{pm_message} pm'; $fragments['select'][] = 'pm.mid'; + // The lowest value is higher than 0 if all recipients have deleted a messageĀ· $fragments['select'][] = 'MIN(pmi.deleted) as is_deleted'; + // The time the most recent deletion happened. $fragments['select'][] = 'MAX(pmi.deleted) as last_deleted'; $fragments['inner_join'][] = 'INNER JOIN {pm_index} pmi ON (pmi.mid = pm.mid)'; $fragments['group_by'][] = 'pm.mid'; + // Ignore messages that have not been deleted by all users. $fragments['having'][] = 'MIN(pmi.deleted) > 0'; + + // Only select messages that have been deleted more than n days ago. $fragments['having'][] = 'MAX(pmi.deleted) < %d'; $fragments['query_args']['having'][] = time() - $days * 86400; }