diff --git a/database.sql b/database.sql index af254f3fe7..ca9fc03201 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2021.03-dev (Red Hot Poker) --- DB_UPDATE_VERSION 1404 +-- DB_UPDATE_VERSION 1405 -- ------------------------------------------ @@ -33,7 +33,8 @@ CREATE TABLE IF NOT EXISTS `gserver` ( `next_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Next connection request', PRIMARY KEY(`id`), UNIQUE INDEX `nurl` (`nurl`(190)), - INDEX `next_contact` (`next_contact`) + INDEX `next_contact` (`next_contact`), + INDEX `network` (`network`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Global servers'; -- @@ -88,6 +89,8 @@ CREATE TABLE IF NOT EXISTS `user` ( PRIMARY KEY(`uid`), INDEX `nickname` (`nickname`(32)), INDEX `parent-uid` (`parent-uid`), + INDEX `guid` (`guid`), + INDEX `email` (`email`(64)), FOREIGN KEY (`parent-uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='The local users'; @@ -192,6 +195,7 @@ CREATE TABLE IF NOT EXISTS `contact` ( INDEX `network_uid_lastupdate` (`network`,`uid`,`last-update`), INDEX `uid_network_self_lastupdate` (`uid`,`network`,`self`,`last-update`), INDEX `uid_lastitem` (`uid`,`last-item`), + INDEX `baseurl` (`baseurl`(64)), INDEX `gsid` (`gsid`), FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT @@ -257,7 +261,8 @@ CREATE TABLE IF NOT EXISTS `permissionset` ( CREATE TABLE IF NOT EXISTS `verb` ( `id` smallint unsigned NOT NULL auto_increment, `name` varchar(100) NOT NULL DEFAULT '' COMMENT '', - PRIMARY KEY(`id`) + PRIMARY KEY(`id`), + INDEX `name` (`name`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Activity Verbs'; -- @@ -313,6 +318,7 @@ CREATE TABLE IF NOT EXISTS `addon` ( `timestamp` int unsigned NOT NULL DEFAULT 0 COMMENT 'file timestamp to check for reloads', `plugin_admin` boolean NOT NULL DEFAULT '0' COMMENT '1 = has admin config, 0 = has no admin config', PRIMARY KEY(`id`), + INDEX `installed_name` (`installed`,`name`), UNIQUE INDEX `name` (`name`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='registered addons'; @@ -414,7 +420,8 @@ CREATE TABLE IF NOT EXISTS `challenge` ( `expire` int unsigned NOT NULL DEFAULT 0 COMMENT '', `type` varchar(255) NOT NULL DEFAULT '' COMMENT '', `last_update` varchar(255) NOT NULL DEFAULT '' COMMENT '', - PRIMARY KEY(`id`) + PRIMARY KEY(`id`), + INDEX `expire` (`expire`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- @@ -627,6 +634,7 @@ CREATE TABLE IF NOT EXISTS `hook` ( `function` varbinary(200) NOT NULL DEFAULT '' COMMENT 'function name of hook handler', `priority` smallint unsigned NOT NULL DEFAULT 0 COMMENT 'not yet implemented - can be used to sort conflicts in hook handling by calling handlers in priority order', PRIMARY KEY(`id`), + INDEX `priority` (`priority`), UNIQUE INDEX `hook_file_function` (`hook`,`file`,`function`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='addon hook registry'; @@ -936,7 +944,6 @@ CREATE TABLE IF NOT EXISTS `post` ( INDEX `author-id` (`author-id`), INDEX `causer-id` (`causer-id`), INDEX `vid` (`vid`), - INDEX `received` (`received`), FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`parent-uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`thr-parent-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, @@ -986,6 +993,7 @@ CREATE TABLE IF NOT EXISTS `post-content` ( `plink` varchar(255) NOT NULL DEFAULT '' COMMENT 'permalink or URL to a displayable copy of the message at its source', PRIMARY KEY(`uri-id`), INDEX `plink` (`plink`(191)), + INDEX `resource-id` (`resource-id`), FULLTEXT INDEX `title-content-warning-body` (`title`,`content-warning`,`body`), FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Content for all posts'; @@ -1108,26 +1116,24 @@ CREATE TABLE IF NOT EXISTS `post-user` ( PRIMARY KEY(`id`), UNIQUE INDEX `uid_uri-id` (`uid`,`uri-id`), INDEX `uri-id` (`uri-id`), - INDEX `contact-id` (`contact-id`), - INDEX `psid` (`psid`), - INDEX `uid_hidden` (`uid`,`hidden`), - INDEX `event-id` (`event-id`), - INDEX `uid_wall` (`uid`,`wall`), - INDEX `parent-uri-id_uid` (`parent-uri-id`,`uid`), + INDEX `parent-uri-id` (`parent-uri-id`), INDEX `thr-parent-id` (`thr-parent-id`), INDEX `external-id` (`external-id`), INDEX `owner-id` (`owner-id`), - INDEX `author-id_uid` (`author-id`,`uid`), + INDEX `author-id` (`author-id`), INDEX `causer-id` (`causer-id`), INDEX `vid` (`vid`), - INDEX `uid_received` (`uid`,`received`), + INDEX `contact-id` (`contact-id`), + INDEX `event-id` (`event-id`), + INDEX `psid` (`psid`), + INDEX `author-id_uid` (`author-id`,`uid`), + INDEX `author-id_received` (`author-id`,`received`), + INDEX `parent-uri-id_uid` (`parent-uri-id`,`uid`), + INDEX `uid_hidden` (`uid`,`hidden`), + INDEX `uid_contactid` (`uid`,`contact-id`), INDEX `uid_unseen_contactid` (`uid`,`unseen`,`contact-id`), - INDEX `uid_network_received` (`uid`,`network`,`received`), - INDEX `uid_contactid_received` (`uid`,`contact-id`,`received`), - INDEX `authorid_received` (`author-id`,`received`), + INDEX `uid_unseen` (`uid`,`unseen`), INDEX `uid_unseen_wall` (`uid`,`unseen`,`wall`), - INDEX `uid_eventid` (`uid`,`event-id`), - INDEX `psid_wall` (`psid`,`wall`), FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`parent-uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`thr-parent-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, @@ -1170,30 +1176,21 @@ CREATE TABLE IF NOT EXISTS `post-thread-user` ( `psid` int unsigned COMMENT 'ID of the permission set of this post', `post-user-id` int unsigned COMMENT 'Id of the post-user table', PRIMARY KEY(`uid`,`uri-id`), - INDEX `uid_wall` (`uid`,`wall`), - INDEX `uid_pinned` (`uid`,`pinned`), INDEX `uri-id` (`uri-id`), + INDEX `owner-id` (`owner-id`), + INDEX `author-id` (`author-id`), + INDEX `causer-id` (`causer-id`), + INDEX `uid` (`uid`), INDEX `contact-id` (`contact-id`), INDEX `psid` (`psid`), INDEX `post-user-id` (`post-user-id`), - INDEX `owner-id` (`owner-id`), - INDEX `causer-id` (`causer-id`), - INDEX `uid_received` (`uid`,`received`), - INDEX `uid_commented` (`uid`,`commented`), - INDEX `uid_changed` (`uid`,`changed`), - INDEX `uid_contact-id` (`uid`,`contact-id`,`received`), - INDEX `uid_unseen_contactid` (`uid`,`unseen`,`contact-id`), - INDEX `uid_network_received` (`uid`,`network`,`received`), - INDEX `uid_network_commented` (`uid`,`network`,`commented`), - INDEX `uid_contact-id_received` (`uid`,`contact-id`,`received`), - INDEX `author-id_received` (`author-id`,`received`), - INDEX `uid_wall_changed` (`uid`,`wall`,`changed`), - INDEX `uid_unseen_wall` (`uid`,`unseen`,`wall`), - INDEX `mention_uid` (`mention`,`uid`), - INDEX `psid_wall` (`psid`,`wall`), - INDEX `received` (`received`), INDEX `commented` (`commented`), - INDEX `changed` (`changed`), + INDEX `received` (`received`), + INDEX `author-id_received` (`author-id`,`received`), + INDEX `uid_pinned` (`uid`,`pinned`), + INDEX `uid_commented` (`uid`,`commented`), + INDEX `mention_uid` (`mention`,`uid`), + INDEX `uid_mention` (`uid`,`mention`), FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`owner-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT, FOREIGN KEY (`author-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT, @@ -1361,7 +1358,8 @@ CREATE TABLE IF NOT EXISTS `search` ( `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `term` varchar(255) NOT NULL DEFAULT '' COMMENT '', PRIMARY KEY(`id`), - INDEX `uid` (`uid`), + INDEX `uid_term` (`uid`,`term`(64)), + INDEX `term` (`term`(64)), FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; @@ -1563,6 +1561,7 @@ CREATE VIEW `post-view` AS SELECT `owner`.`network` AS `owner-network`, `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, + `owner`.`contact-type` AS `owner-contact-type`, `post-user`.`causer-id` AS `causer-id`, `causer`.`url` AS `causer-link`, `causer`.`addr` AS `causer-addr`, @@ -1603,9 +1602,9 @@ CREATE VIEW `post-view` AS SELECT `parent-post-author`.`network` AS `parent-author-network` FROM `post-user` STRAIGHT_JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` - LEFT JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id` - LEFT JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id` - LEFT JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id` + STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id` + STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id` + STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id` LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-user`.`causer-id` LEFT JOIN `item-uri` ON `item-uri`.`id` = `post-user`.`uri-id` LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-user`.`thr-parent-id` @@ -1720,6 +1719,7 @@ CREATE VIEW `post-thread-view` AS SELECT `owner`.`network` AS `owner-network`, `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, + `owner`.`contact-type` AS `owner-contact-type`, `post-thread-user`.`causer-id` AS `causer-id`, `causer`.`url` AS `causer-link`, `causer`.`addr` AS `causer-addr`, @@ -1760,9 +1760,9 @@ CREATE VIEW `post-thread-view` AS SELECT `parent-post-author`.`network` AS `parent-author-network` FROM `post-thread-user` INNER JOIN `post-user` ON `post-user`.`id` = `post-thread-user`.`post-user-id` - LEFT JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` - LEFT JOIN `contact` AS `author` ON `author`.`id` = `post-thread-user`.`author-id` - LEFT JOIN `contact` AS `owner` ON `owner`.`id` = `post-thread-user`.`owner-id` + STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` + STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-thread-user`.`author-id` + STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-thread-user`.`owner-id` LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-thread-user`.`causer-id` LEFT JOIN `item-uri` ON `item-uri`.`id` = `post-thread-user`.`uri-id` LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-user`.`thr-parent-id` diff --git a/include/conversation.php b/include/conversation.php index 193dc33e2f..b74b1f152b 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -145,7 +145,7 @@ function localize_item(&$item) $item['body'] = item_redir_and_replace_images($extracted['body'], $extracted['images'], $item['contact-id']); } - /// @todo The following functionality needs to be cleaned up. + /// @todo The following functionality needs to be cleaned up. if (!empty($item['verb'])) { $activity = DI::activity(); @@ -481,7 +481,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o 'attendyes' => [], 'attendno' => [], 'attendmaybe' => [], - 'announce' => [], + 'announce' => [], ]; if (DI::pConfig()->get(local_user(), 'system', 'hide_dislike')) { @@ -839,8 +839,8 @@ function conversation_add_children(array $parents, $block_authors, $order, $uid) $activity = ['causer-id' => $parent['author-id']]; foreach (['commented', 'received', 'created'] as $orderfields) { if (!empty($parent[$orderfields])) { - $activity[$orderfields] = $parent[$orderfields]; - } + $activity[$orderfields] = $parent[$orderfields]; + } } } } else { diff --git a/src/Database/DBA.php b/src/Database/DBA.php index 3bdcfb617a..56e8891aae 100644 --- a/src/Database/DBA.php +++ b/src/Database/DBA.php @@ -767,13 +767,15 @@ class DBA /** * Fills an array with data from a query * - * @param object $stmt statement object - * @param bool $do_close + * @param object $stmt statement object + * @param bool $do_close Close database connection after last row + * @param int $count maximum number of rows to be fetched + * * @return array Data array */ - public static function toArray($stmt, $do_close = true) + public static function toArray($stmt, $do_close = true, int $count = 0) { - return DI::dba()->toArray($stmt, $do_close); + return DI::dba()->toArray($stmt, $do_close, $count); } /** diff --git a/src/Database/Database.php b/src/Database/Database.php index ec95a8301c..653fd0393d 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1613,12 +1613,13 @@ class Database /** * Fills an array with data from a query * - * @param object $stmt statement object - * @param bool $do_close + * @param object $stmt statement object + * @param bool $do_close Close database connection after last row + * @param int $count maximum number of rows to be fetched * * @return array Data array */ - public function toArray($stmt, $do_close = true) + public function toArray($stmt, $do_close = true, int $count = 0) { if (is_bool($stmt)) { return []; @@ -1627,6 +1628,9 @@ class Database $data = []; while ($row = $this->fetch($stmt)) { $data[] = $row; + if (($count != 0) && (count($data) == $count)) { + return $data; + } } if ($do_close) { diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 3029413853..f96c556d24 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -2688,10 +2688,6 @@ class Contact return $destination; } - if (!empty($contact['uid']) || empty($contact['network'])) { - return self::magicLink($contact['url'], $url); - } - if (empty($contact['id'])) { return $destination; } diff --git a/src/Model/Item.php b/src/Model/Item.php index 9046674e7b..7a28ddd1c9 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -78,7 +78,7 @@ class Item 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network', - 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'owner-network', + 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'causer-id', 'causer-link', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', 'contact-id', 'contact-uid', 'contact-link', 'contact-name', 'contact-avatar', 'writable', 'self', 'cid', 'alias', @@ -115,22 +115,6 @@ class Item 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network', 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'causer-id']; - // Item fields that still are in use - const USED_FIELDLIST = ['id', 'parent', 'guid', 'uri', 'uri-id', 'parent-uri', 'parent-uri-id', - 'thr-parent', 'thr-parent-id', 'created', 'edited', 'commented', 'received', 'changed', - 'gravity', 'network', 'owner-id', 'author-id', 'causer-id', 'vid', 'extid', 'post-type', - 'global', 'private', 'visible', 'deleted', 'uid', 'contact-id', - 'wall', 'origin', 'pubmail', 'starred', 'unseen', 'mention', 'forum_mode', 'psid', - 'event-id']; - - // Legacy item fields that aren't stored any more in the item table - const LEGACY_FIELDLIST = ['uri-hash', 'iaid', 'icid', 'attach', - 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'postopts', - 'resource-id', 'inform', 'file', 'location', 'coord', 'tag', 'plink', - 'title', 'content-warning', 'body', 'app', 'verb', 'object-type', 'object', - 'target-type', 'target', 'author-name', 'author-link', 'author-avatar', - 'owner-name', 'owner-link', 'owner-avatar', 'rendered-hash', 'rendered-html']; - // List of all verbs that don't need additional content data. // Never reorder or remove entries from this list. Just add new ones at the end, if needed. const ACTIVITIES = [ @@ -882,6 +866,8 @@ class Item $item['wall'] = $toplevel_parent['wall']; } else { $item['wall'] = false; + // Participations are technical messages, so they are set to "seen" automatically + $item['unseen'] = false; } /* @@ -2513,12 +2499,11 @@ class Item * Body is preserved to avoid side-effects as we modify it just-in-time for spoilers and private image links * * @param array $item - * @param bool $update * * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Remove reference, simply return "rendered-html" and "rendered-hash" */ - public static function putInCache(&$item, $update = false) + public static function putInCache(&$item) { // Save original body to prevent addons to modify it $body = $item['body']; @@ -2542,17 +2527,8 @@ class Item $item['rendered-hash'] = $hook_data['rendered-hash']; unset($hook_data); - // Force an update if the generated values differ from the existing ones - if ($rendered_hash != $item['rendered-hash']) { - $update = true; - } - - // Only compare the HTML when we forcefully ignore the cache - if (DI::config()->get('system', 'ignore_cache') && ($rendered_html != $item['rendered-html'])) { - $update = true; - } - - if ($update && !empty($item['id'])) { + // Update if the generated values differ from the existing ones + if ((($rendered_hash != $item['rendered-hash']) || ($rendered_html != $item['rendered-html'])) && !empty($item['id'])) { self::update( [ 'rendered-html' => $item['rendered-html'], @@ -2640,15 +2616,7 @@ class Item unset($hook_data); } - // Update the cached values if there is no "zrl=..." on the links. - $update = (!Session::isAuthenticated() && ($item["uid"] == 0)); - - // Or update it if the current viewer is the intented viewer. - if (($item["uid"] == local_user()) && ($item["uid"] != 0)) { - $update = true; - } - - self::putInCache($item, $update); + self::putInCache($item); $s = $item["rendered-html"]; $hook_data = [ diff --git a/src/Model/Nodeinfo.php b/src/Model/Nodeinfo.php index ef22c0dddf..5240bc0802 100644 --- a/src/Model/Nodeinfo.php +++ b/src/Model/Nodeinfo.php @@ -58,18 +58,14 @@ class Nodeinfo $config->set('nodeinfo', 'active_users_monthly', $userStats['active_users_monthly']); $config->set('nodeinfo', 'active_users_weekly', $userStats['active_users_weekly']); - $logger->debug('user statistics', $userStats); + $logger->info('user statistics', $userStats); - $items = DBA::p("SELECT COUNT(*) AS `total`, `gravity` FROM `post-view` WHERE `origin` AND NOT `deleted` AND `uid` != 0 AND `gravity` IN (?, ?) GROUP BY `gravity`", - GRAVITY_PARENT, GRAVITY_COMMENT); - while ($item = DBA::fetch($items)) { - if ($item['gravity'] == GRAVITY_PARENT) { - $config->set('nodeinfo', 'local_posts', $item['total']); - } elseif ($item['gravity'] == GRAVITY_COMMENT) { - $config->set('nodeinfo', 'local_comments', $item['total']); - } - } - DBA::close($items); + $posts = DBA::count('post-thread', ["EXISTS(SELECT `uri-id` FROM `post-user` WHERE NOT `deleted` AND `origin` AND `uri-id` = `post-thread`.`uri-id`)"]); + $comments = DBA::count('post', ["NOT `deleted` AND `gravity` = ? AND EXISTS(SELECT `uri-id` FROM `post-user` WHERE `origin` AND `uri-id` = `post`.`uri-id`)", GRAVITY_COMMENT]); + $config->set('nodeinfo', 'local_posts', $posts); + $config->set('nodeinfo', 'local_comments', $comments); + + $logger->info('User actitivy', ['posts' => $posts, 'comments' => $comments]); } /** diff --git a/src/Model/Post.php b/src/Model/Post.php index e3114ca909..36e4a5f663 100644 --- a/src/Model/Post.php +++ b/src/Model/Post.php @@ -23,6 +23,7 @@ namespace Friendica\Model; use BadMethodCallException; use Friendica\Core\Logger; +use Friendica\Core\System; use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\Database\DBStructure; @@ -421,7 +422,7 @@ class Post { $affected = 0; - Logger::info('Start Update', ['fields' => $fields, 'condition' => $condition]); + Logger::info('Start Update', ['fields' => $fields, 'condition' => $condition, 'uid' => local_user(),'callstack' => System::callstack(10)]); // Don't allow changes to fields that are responsible for the relation between the records unset($fields['id']); @@ -441,78 +442,104 @@ class Post $update_fields = DBStructure::getFieldsForTable('post-user', $fields); if (!empty($update_fields)) { - $rows = DBA::selectToArray('post-view', ['post-user-id'], $condition); - $puids = array_column($rows, 'post-user-id'); - if (!DBA::update('post-user', $update_fields, ['id' => $puids])) { - DBA::rollback(); - Logger::notice('Updating post-user failed', ['fields' => $update_fields, 'condition' => $condition]); - return false; + $affected_count = 0; + $posts = DBA::select('post-view', ['post-user-id'], $condition); + while ($rows = DBA::toArray($posts, false, 100)) { + $puids = array_column($rows, 'post-user-id'); + if (!DBA::update('post-user', $update_fields, ['id' => $puids])) { + DBA::rollback(); + Logger::notice('Updating post-user failed', ['fields' => $update_fields, 'condition' => $condition]); + return false; + } + $affected_count += DBA::affectedRows(); } - $affected = DBA::affectedRows(); + DBA::close($posts); + $affected = $affected_count; } $update_fields = DBStructure::getFieldsForTable('post-content', $fields); if (!empty($update_fields)) { - $rows = DBA::selectToArray('post-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); - $uriids = array_column($rows, 'uri-id'); - if (!DBA::update('post-content', $update_fields, ['uri-id' => $uriids])) { - DBA::rollback(); - Logger::notice('Updating post-content failed', ['fields' => $update_fields, 'condition' => $condition]); - return false; + $affected_count = 0; + $posts = DBA::select('post-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); + while ($rows = DBA::toArray($posts, false, 100)) { + $uriids = array_column($rows, 'uri-id'); + if (!DBA::update('post-content', $update_fields, ['uri-id' => $uriids])) { + DBA::rollback(); + Logger::notice('Updating post-content failed', ['fields' => $update_fields, 'condition' => $condition]); + return false; + } + $affected_count += DBA::affectedRows(); } - $affected = max($affected, DBA::affectedRows()); + DBA::close($posts); + $affected = max($affected, $affected_count); } $update_fields = DBStructure::getFieldsForTable('post', $fields); if (!empty($update_fields)) { - if (empty($uriids)) { - $rows = DBA::selectToArray('post-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); + $affected_count = 0; + $posts = DBA::select('post-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); + while ($rows = DBA::toArray($posts, false, 100)) { $uriids = array_column($rows, 'uri-id'); + if (!DBA::update('post', $update_fields, ['uri-id' => $uriids])) { + DBA::rollback(); + Logger::notice('Updating post failed', ['fields' => $update_fields, 'condition' => $condition]); + return false; + } + $affected_count += DBA::affectedRows(); } - if (!DBA::update('post', $update_fields, ['uri-id' => $uriids])) { - DBA::rollback(); - Logger::notice('Updating post failed', ['fields' => $update_fields, 'condition' => $condition]); - return false; - } - $affected = max($affected, DBA::affectedRows()); + DBA::close($posts); + $affected = max($affected, $affected_count); } $update_fields = Post\DeliveryData::extractFields($fields); if (!empty($update_fields)) { - if (empty($uriids)) { - $rows = DBA::selectToArray('post-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); + $affected_count = 0; + $posts = DBA::select('post-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); + while ($rows = DBA::toArray($posts, false, 100)) { $uriids = array_column($rows, 'uri-id'); + if (!DBA::update('post-delivery-data', $update_fields, ['uri-id' => $uriids])) { + DBA::rollback(); + Logger::notice('Updating post-delivery-data failed', ['fields' => $update_fields, 'condition' => $condition]); + return false; + } + $affected_count += DBA::affectedRows(); } - if (!DBA::update('post-delivery-data', $update_fields, ['uri-id' => $uriids])) { - DBA::rollback(); - Logger::notice('Updating post-delivery-data failed', ['fields' => $update_fields, 'condition' => $condition]); - return false; - } - $affected = max($affected, DBA::affectedRows()); + DBA::close($posts); + $affected = max($affected, $affected_count); } $update_fields = DBStructure::getFieldsForTable('post-thread', $fields); if (!empty($update_fields)) { - $rows = DBA::selectToArray('post-view', ['uri-id'], $thread_condition, ['group_by' => ['uri-id']]); - $uriids = array_column($rows, 'uri-id'); - if (!DBA::update('post-thread', $update_fields, ['uri-id' => $uriids])) { - DBA::rollback(); - Logger::notice('Updating post-thread failed', ['fields' => $update_fields, 'condition' => $condition]); - return false; + $affected_count = 0; + $posts = DBA::select('post-view', ['uri-id'], $thread_condition, ['group_by' => ['uri-id']]); + while ($rows = DBA::toArray($posts, false, 100)) { + $uriids = array_column($rows, 'uri-id'); + if (!DBA::update('post-thread', $update_fields, ['uri-id' => $uriids])) { + DBA::rollback(); + Logger::notice('Updating post-thread failed', ['fields' => $update_fields, 'condition' => $condition]); + return false; + } + $affected_count += DBA::affectedRows(); } - $affected = max($affected, DBA::affectedRows()); + DBA::close($posts); + $affected = max($affected, $affected_count); } $update_fields = DBStructure::getFieldsForTable('post-thread-user', $fields); if (!empty($update_fields)) { - $rows = DBA::selectToArray('post-view', ['post-user-id'], $thread_condition); - $thread_puids = array_column($rows, 'post-user-id'); - if (!DBA::update('post-thread-user', $update_fields, ['post-user-id' => $thread_puids])) { - DBA::rollback(); - Logger::notice('Updating post-thread-user failed', ['fields' => $update_fields, 'condition' => $condition]); - return false; + $affected_count = 0; + $posts = DBA::select('post-view', ['post-user-id'], $thread_condition); + while ($rows = DBA::toArray($posts, false, 100)) { + $thread_puids = array_column($rows, 'post-user-id'); + if (!DBA::update('post-thread-user', $update_fields, ['post-user-id' => $thread_puids])) { + DBA::rollback(); + Logger::notice('Updating post-thread-user failed', ['fields' => $update_fields, 'condition' => $condition]); + return false; + } + $affected_count += DBA::affectedRows(); } - $affected = max($affected, DBA::affectedRows()); + DBA::close($posts); + $affected = max($affected, $affected_count); } DBA::commit(); diff --git a/src/Module/Conversation/Community.php b/src/Module/Conversation/Community.php index 026c31f1d1..dc4a7c9918 100644 --- a/src/Module/Conversation/Community.php +++ b/src/Module/Conversation/Community.php @@ -315,13 +315,13 @@ class Community extends BaseModule { if (self::$content == 'local') { if (!is_null(self::$accountType)) { - $condition = ["`wall` AND `origin` AND `private` = ? AND `owner`.`contact-type` = ?", Item::PUBLIC, self::$accountType]; + $condition = ["`wall` AND `origin` AND `private` = ? AND `owner-contact-type` = ?", Item::PUBLIC, self::$accountType]; } else { $condition = ["`wall` AND `origin` AND `private` = ?", Item::PUBLIC]; } } elseif (self::$content == 'global') { if (!is_null(self::$accountType)) { - $condition = ["`uid` = ? AND `private` = ? AND `owner`.`contact-type` = ?", 0, Item::PUBLIC, self::$accountType]; + $condition = ["`uid` = ? AND `private` = ? AND `owner-contact-type` = ?", 0, Item::PUBLIC, self::$accountType]; } else { $condition = ["`uid` = ? AND `private` = ?", 0, Item::PUBLIC]; } diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index be87da5f68..c093cc9ca6 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -306,12 +306,21 @@ class Network extends BaseModule if (!empty($get['order'])) { self::$selectedTab = $get['order']; self::$order = $get['order']; + self::$star = false; + self::$mention = false; } elseif (in_array(self::$selectedTab, ['received', 'star', 'mention'])) { self::$order = 'received'; } self::$selectedTab = self::$selectedTab ?? self::$order; + // Prohibit combined usage of "star" and "mention" + if (self::$selectedTab == 'star') { + self::$mention = false; + } elseif (self::$selectedTab == 'mention') { + self::$star = false; + } + Session::set('network-tab', self::$selectedTab); DI::pConfig()->set(local_user(), 'network.view', 'selected_tab', self::$selectedTab); diff --git a/src/Module/Profile/Status.php b/src/Module/Profile/Status.php index 267e3c1892..7c3875e46c 100644 --- a/src/Module/Profile/Status.php +++ b/src/Module/Profile/Status.php @@ -181,9 +181,9 @@ class Status extends BaseProfile $condition = DBA::mergeConditions($condition, ["((`gravity` = ? AND `wall`) OR (`gravity` = ? AND `vid` = ? AND `origin` AND `thr-parent-id` IN - (SELECT `uri-id` FROM `post-view` AS `i` + (SELECT `uri-id` FROM `post-view` WHERE `gravity` = ? AND `network` IN (?, ?, ?, ?) AND `uid` IN (?, ?) - AND `i`.`uri-id` = `thr-parent-id`)))", + AND `uri-id` = `thr-parent-id`)))", GRAVITY_PARENT, GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), GRAVITY_PARENT, Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::DIASPORA, Protocol::OSTATUS, 0, $a->profile['uid']]); diff --git a/src/Module/Update/Profile.php b/src/Module/Update/Profile.php index bab1a63a34..8dcd88e6ac 100644 --- a/src/Module/Update/Profile.php +++ b/src/Module/Update/Profile.php @@ -81,7 +81,7 @@ class Profile extends BaseModule } $items_stmt = DBA::p( - "SELECT DISTINCT(`parent-uri-id`) AS `uri-id`, `created` FROM `post-view` + "SELECT DISTINCT(`parent-uri-id`) AS `uri-id`, MAX(`created`), MAX(`received`) FROM `post-view` WHERE `uid` = ? AND NOT `contact-blocked` AND NOT `contact-pending` AND `visible` AND (NOT `deleted` OR `gravity` = ?) AND `wall` $sql_extra4 $sql_extra diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 14c8df1a78..950e8dc552 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -3099,17 +3099,7 @@ class Diaspora return; } - // Fetch some user id to have a valid handle to transmit the participation. - // In fact it doesn't matter which user sends this - but it is needed by the protocol. - // If the item belongs to a user, we take this user id. - if ($item['uid'] == 0) { - $condition = ['verified' => true, 'blocked' => false, 'account_removed' => false, 'account_expired' => false]; - $first_user = DBA::selectFirst('user', ['uid'], $condition); - $owner = User::getOwnerDataById($first_user['uid']); - } else { - $owner = User::getOwnerDataById($item['uid']); - } - + $owner = User::getOwnerDataById($item['uid']); $author = self::myHandle($owner); $message = ["author" => $author, diff --git a/src/Worker/CleanItemUri.php b/src/Worker/CleanItemUri.php index 8f74d99fb0..84ef537c42 100644 --- a/src/Worker/CleanItemUri.php +++ b/src/Worker/CleanItemUri.php @@ -41,11 +41,20 @@ class CleanItemUri return; } Logger::notice('Start deleting orphaned URI-ID', ['last-id' => $item['uri-id']]); - $ret = DBA::e("DELETE FROM `item-uri` WHERE `id` < ? - AND NOT EXISTS(SELECT `uri-id` FROM `post-user` WHERE `uri-id` = `item-uri`.`id`) - AND NOT EXISTS(SELECT `parent-uri-id` FROM `post-user` WHERE `parent-uri-id` = `item-uri`.`id`) - AND NOT EXISTS(SELECT `thr-parent-id` FROM `post-user` WHERE `thr-parent-id` = `item-uri`.`id`) - AND NOT EXISTS(SELECT `external-id` FROM `post-user` WHERE `external-id` = `item-uri`.`id`)", $item['uri-id']); - Logger::notice('Orphaned URI-ID entries removed', ['result' => $ret, 'rows' => DBA::affectedRows()]); + $uris = DBA::select('item-uri', ['id'], ["`id` < ? + AND NOT EXISTS(SELECT `uri-id` FROM `post` WHERE `uri-id` = `item-uri`.`id`) + AND NOT EXISTS(SELECT `parent-uri-id` FROM `post` WHERE `parent-uri-id` = `item-uri`.`id`) + AND NOT EXISTS(SELECT `thr-parent-id` FROM `post` WHERE `thr-parent-id` = `item-uri`.`id`) + AND NOT EXISTS(SELECT `external-id` FROM `post` WHERE `external-id` = `item-uri`.`id`)", $item['uri-id']]); + + $affected_count = 0; + while ($rows = DBA::toArray($uris, false, 100)) { + $ids = array_column($rows, 'id'); + DBA::delete('item-uri', ['id' => $ids]); + $affected_count += DBA::affectedRows(); + Logger::info('Deleted', ['rows' => $affected_count]); + } + DBA::close($uris); + Logger::notice('Orphaned URI-ID entries removed', ['rows' => $affected_count]); } } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 8013b928f1..79c4fb62b9 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1404); + define('DB_UPDATE_VERSION', 1405); } return [ @@ -91,6 +91,7 @@ return [ "PRIMARY" => ["id"], "nurl" => ["UNIQUE", "nurl(190)"], "next_contact" => ["next_contact"], + "network" => ["network"], ] ], "user" => [ @@ -147,6 +148,8 @@ return [ "PRIMARY" => ["uid"], "nickname" => ["nickname(32)"], "parent-uid" => ["parent-uid"], + "guid" => ["guid"], + "email" => ["email(64)"], ] ], "contact" => [ @@ -251,6 +254,7 @@ return [ "network_uid_lastupdate" => ["network", "uid", "last-update"], "uid_network_self_lastupdate" => ["uid", "network", "self", "last-update"], "uid_lastitem" => ["uid", "last-item"], + "baseurl" => ["baseurl(64)"], "gsid" => ["gsid"] ] ], @@ -317,7 +321,8 @@ return [ "name" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => ""] ], "indexes" => [ - "PRIMARY" => ["id"] + "PRIMARY" => ["id"], + "name" => ["name"] ] ], // Main tables @@ -375,6 +380,7 @@ return [ ], "indexes" => [ "PRIMARY" => ["id"], + "installed_name" => ["installed", "name"], "name" => ["UNIQUE", "name"], ] ], @@ -480,6 +486,7 @@ return [ ], "indexes" => [ "PRIMARY" => ["id"], + "expire" => ["expire"], ] ], "config" => [ @@ -693,6 +700,7 @@ return [ ], "indexes" => [ "PRIMARY" => ["id"], + "priority" => ["priority"], "hook_file_function" => ["UNIQUE", "hook", "file", "function"], ] ], @@ -1002,7 +1010,6 @@ return [ "author-id" => ["author-id"], "causer-id" => ["causer-id"], "vid" => ["vid"], - "received" => ["received"], ] ], "post-category" => [ @@ -1043,6 +1050,7 @@ return [ "indexes" => [ "PRIMARY" => ["uri-id"], "plink" => ["plink(191)"], + "resource-id" => ["resource-id"], "title-content-warning-body" => ["FULLTEXT", "title", "content-warning", "body"], ] ], @@ -1110,7 +1118,7 @@ return [ "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""], "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], "received" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], - "changed" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date that something in the conversation changed, indicating clients should fetch the conversation again"], + "changed" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date that something in the conversation changed, indicating clients should fetch the conversation again"], "commented" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""] ], "indexes" => [ @@ -1160,26 +1168,24 @@ return [ "PRIMARY" => ["id"], "uid_uri-id" => ["UNIQUE", "uid", "uri-id"], "uri-id" => ["uri-id"], - "contact-id" => ["contact-id"], - "psid" => ["psid"], - "uid_hidden" => ["uid", "hidden"], - "event-id" => ["event-id"], - "uid_wall" => ["uid", "wall"], - "parent-uri-id_uid" => ["parent-uri-id", "uid"], + "parent-uri-id" => ["parent-uri-id"], "thr-parent-id" => ["thr-parent-id"], "external-id" => ["external-id"], "owner-id" => ["owner-id"], - "author-id_uid" => ["author-id", "uid"], + "author-id" => ["author-id"], "causer-id" => ["causer-id"], "vid" => ["vid"], - "uid_received" => ["uid", "received"], + "contact-id" => ["contact-id"], + "event-id" => ["event-id"], + "psid" => ["psid"], + "author-id_uid" => ["author-id", "uid"], + "author-id_received" => ["author-id", "received"], + "parent-uri-id_uid" => ["parent-uri-id", "uid"], + "uid_hidden" => ["uid", "hidden"], + "uid_contactid" => ["uid", "contact-id"], "uid_unseen_contactid" => ["uid", "unseen", "contact-id"], - "uid_network_received" => ["uid", "network", "received"], - "uid_contactid_received" => ["uid", "contact-id", "received"], - "authorid_received" => ["author-id", "received"], + "uid_unseen" => ["uid", "unseen"], "uid_unseen_wall" => ["uid", "unseen", "wall"], - "uid_eventid" => ["uid", "event-id"], - "psid_wall" => ["psid", "wall"], ], ], "post-thread-user" => [ @@ -1211,30 +1217,21 @@ return [ ], "indexes" => [ "PRIMARY" => ["uid", "uri-id"], - "uid_wall" => ["uid", "wall"], - "uid_pinned" => ["uid", "pinned"], "uri-id" => ["uri-id"], + "owner-id" => ["owner-id"], + "author-id" => ["author-id"], + "causer-id" => ["causer-id"], + "uid" => ["uid"], "contact-id" => ["contact-id"], "psid" => ["psid"], "post-user-id" => ["post-user-id"], - "owner-id" => ["owner-id"], - "causer-id" => ["causer-id"], - "uid_received" => ["uid", "received"], - "uid_commented" => ["uid", "commented"], - "uid_changed" => ["uid", "changed"], - "uid_contact-id" => ["uid", "contact-id", "received"], - "uid_unseen_contactid" => ["uid", "unseen", "contact-id"], - "uid_network_received" => ["uid", "network", "received"], - "uid_network_commented" => ["uid", "network", "commented"], - "uid_contact-id_received" => ["uid", "contact-id", "received"], - "author-id_received" => ["author-id", "received"], - "uid_wall_changed" => ["uid", "wall", "changed"], - "uid_unseen_wall" => ["uid", "unseen", "wall"], - "mention_uid" => ["mention", "uid"], - "psid_wall" => ["psid", "wall"], - "received" => ["received"], "commented" => ["commented"], - "changed" => ["changed"], + "received" => ["received"], + "author-id_received" => ["author-id", "received"], + "uid_pinned" => ["uid", "pinned"], + "uid_commented" => ["uid", "commented"], + "mention_uid" => ["mention", "uid"], + "uid_mention" => ["uid", "mention"], ] ], "post-user-notification" => [ @@ -1393,7 +1390,8 @@ return [ ], "indexes" => [ "PRIMARY" => ["id"], - "uid" => ["uid"], + "uid_term" => ["uid", "term(64)"], + "term" => ["term(64)"] ] ], "session" => [ diff --git a/static/dbview.config.php b/static/dbview.config.php index 5e5630fc96..cfca9d07ae 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -134,11 +134,12 @@ "owner-network" => ["owner", "network"], "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], + "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-user", "causer-id"], "causer-link" => ["causer", "url"], "causer-addr" => ["causer", "addr"], "causer-name" => ["causer", "name"], - "causer-nick" => ["causer", "nick"], + "causer-nick" => ["causer", "nick"], "causer-avatar" => ["causer", "thumb"], "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], @@ -169,15 +170,15 @@ "parent-guid" => ["parent-item-uri", "guid"], "parent-network" => ["parent-post", "network"], "parent-author-id" => ["parent-post", "author-id"], - "parent-author-link" => ["parent-post-author", "url"], + "parent-author-link" => ["parent-post-author", "url"], "parent-author-name" => ["parent-post-author", "name"], - "parent-author-network" => ["parent-post-author", "network"], + "parent-author-network" => ["parent-post-author", "network"], ], "query" => "FROM `post-user` STRAIGHT_JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` - LEFT JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id` - LEFT JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id` - LEFT JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id` + STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id` + STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id` + STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id` LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-user`.`causer-id` LEFT JOIN `item-uri` ON `item-uri`.`id` = `post-user`.`uri-id` LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-user`.`thr-parent-id` @@ -289,11 +290,12 @@ "owner-network" => ["owner", "network"], "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], + "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-thread-user", "causer-id"], "causer-link" => ["causer", "url"], "causer-addr" => ["causer", "addr"], "causer-name" => ["causer", "name"], - "causer-nick" => ["causer", "nick"], + "causer-nick" => ["causer", "nick"], "causer-avatar" => ["causer", "thumb"], "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], @@ -324,15 +326,15 @@ "parent-guid" => ["parent-item-uri", "guid"], "parent-network" => ["parent-post", "network"], "parent-author-id" => ["parent-post", "author-id"], - "parent-author-link" => ["parent-post-author", "url"], + "parent-author-link" => ["parent-post-author", "url"], "parent-author-name" => ["parent-post-author", "name"], - "parent-author-network" => ["parent-post-author", "network"], + "parent-author-network" => ["parent-post-author", "network"], ], "query" => "FROM `post-thread-user` INNER JOIN `post-user` ON `post-user`.`id` = `post-thread-user`.`post-user-id` - LEFT JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` - LEFT JOIN `contact` AS `author` ON `author`.`id` = `post-thread-user`.`author-id` - LEFT JOIN `contact` AS `owner` ON `owner`.`id` = `post-thread-user`.`owner-id` + STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` + STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-thread-user`.`author-id` + STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-thread-user`.`owner-id` LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-thread-user`.`causer-id` LEFT JOIN `item-uri` ON `item-uri`.`id` = `post-thread-user`.`uri-id` LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-user`.`thr-parent-id`