From c472f00445a91331e396511229f469de70302588 Mon Sep 17 00:00:00 2001 From: wn_ Date: Sat, 17 May 2025 19:08:12 +0000 Subject: [PATCH] Get rid of 'Db::past_comparison_qpart()'. With MySQL support dropped this function is just an unnecessary layer of abstraction. --- classes/Db.php | 20 -------------------- classes/Digest.php | 9 ++------- classes/Feeds.php | 21 +++++++++------------ classes/RPC.php | 3 +-- classes/RSSUtils.php | 35 ++++++++++++----------------------- update.php | 4 +--- 6 files changed, 25 insertions(+), 67 deletions(-) diff --git a/classes/Db.php b/classes/Db.php index 872c6b351..0017fdf03 100644 --- a/classes/Db.php +++ b/classes/Db.php @@ -75,24 +75,4 @@ class Db { public static function sql_random_function(): string { return "RANDOM()"; } - - /** - * Helper to build a query part comparing a field against a past datetime (determined by "$now - $some_interval") - * - * The example below could be read as "last_digest_sent is older than 1 day ago". - * ```php - * Db::past_comparison_qpart('last_digest_sent', '<', 1, 'day'); - * ``` - * - * @todo validate value of $unit and fail if invalid (or massage if practical)? - * @link https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-INTERVAL-INPUT - * @param string $field the table field being checked - * @param '<'|'>'|'<='|'>='|'=' $operator the comparison operator - * @param positive-int $quantity the amount of $unit - * @param 'year'|'month'|'week'|'day'|'hour'|'minute'|'second' $unit the unit of time for $quantity (see links for more info) - * @return string the query part string - */ - static function past_comparison_qpart(string $field, string $operator, int $quantity, string $unit): string { - return "$field $operator NOW() - INTERVAL '$quantity $unit' "; - } } diff --git a/classes/Digest.php b/classes/Digest.php index 05b735510..f0ffafcbf 100644 --- a/classes/Digest.php +++ b/classes/Digest.php @@ -7,12 +7,10 @@ class Digest Debug::log("Sending digests, batch of max $user_limit users, headline limit = $limit"); - $interval_qpart = Db::past_comparison_qpart('last_digest_sent', '<', 1, 'day'); - $pdo = Db::pdo(); $res = $pdo->query("SELECT id, login, email FROM ttrss_users - WHERE email != '' AND (last_digest_sent IS NULL OR $interval_qpart)"); + WHERE email != '' AND (last_digest_sent IS NULL OR last_digest_sent < NOW() - INTERVAL '1 day')"); while ($line = $res->fetch()) { @@ -102,9 +100,6 @@ class Digest $tpl_t->setVariable('TTRSS_HOST', Config::get_self_url()); $affected_ids = array(); - - $interval_qpart = Db::past_comparison_qpart('ttrss_entries.date_updated', '>', $days, 'day'); - $pdo = Db::pdo(); $sth = $pdo->prepare("SELECT ttrss_entries.title, @@ -123,7 +118,7 @@ class Digest WHERE ref_id = ttrss_entries.id AND feed_id = ttrss_feeds.id AND include_in_digest = true - AND $interval_qpart + AND ttrss_entries.date_updated > NOW() - INTERVAL '$days day' AND ttrss_user_entries.owner_uid = :user_id AND unread = true AND score >= :min_score diff --git a/classes/Feeds.php b/classes/Feeds.php index bea3bb0f4..7640185c1 100644 --- a/classes/Feeds.php +++ b/classes/Feeds.php @@ -754,7 +754,7 @@ class Feeds extends Handler_Protected { } $date_qpart = match ($mode) { - '1day', '1week', '2week' => Db::past_comparison_qpart('date_entered', '<', (int) substr($mode, 0, 1), substr($mode, 1)), + '1day', '1week', '2week' => "date_entered < NOW() - INTERVAL '" . (int) substr($mode, 0, 1) . " " . substr($mode, 1) . "'", default => 'true', }; @@ -827,13 +827,12 @@ class Feeds extends Handler_Protected { $intl = (int) Prefs::get(Prefs::FRESH_ARTICLE_MAX_AGE, $owner_uid, $profile); - $match_part = Db::past_comparison_qpart('date_entered', '>', $intl, 'hour'); - $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id - AND owner_uid = ? AND score >= 0 AND unread = true AND $date_qpart AND $match_part AND $search_qpart) as tmp)"); + AND owner_uid = ? AND score >= 0 AND unread = true AND date_entered > NOW() - INTERVAL '$intl hour' + AND $date_qpart AND $search_qpart) as tmp)"); $sth->execute([$owner_uid]); } @@ -919,7 +918,7 @@ class Feeds extends Handler_Protected { $match_part = "published = true"; } else if ($n_feed == Feeds::FEED_FRESH) { $intl = (int) Prefs::get(Prefs::FRESH_ARTICLE_MAX_AGE, $owner_uid, $profile); - $match_part = 'unread = true AND score >= 0 AND ' . Db::past_comparison_qpart('date_entered', '>', $intl, 'hour'); + $match_part = "unread = true AND score >= 0 AND date_entered > NOW() - INTERVAL '$intl hour'"; $need_entries = true; @@ -1530,8 +1529,8 @@ class Feeds extends Handler_Protected { } } else if ($feed == Feeds::FEED_RECENTLY_READ) { // recently read - $query_strategy_part = 'unread = false AND last_read IS NOT NULL AND ' - . Db::past_comparison_qpart('last_read', '>', 1, 'day'); + $query_strategy_part = "unread = false AND last_read IS NOT NULL AND + last_read > NOW() - INTERVAL '1 day'"; $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; $allow_archived = true; @@ -1542,8 +1541,8 @@ class Feeds extends Handler_Protected { } else if ($feed == Feeds::FEED_FRESH) { // fresh virtual feed $intl = (int) Prefs::get(Prefs::FRESH_ARTICLE_MAX_AGE, $owner_uid, $profile); - $query_strategy_part = 'unread = true AND score >= 0 AND ' - . Db::past_comparison_qpart('date_entered', '>', $intl, 'hour'); + $query_strategy_part = "unread = true AND score >= 0 AND + date_entered > NOW() - INTERVAL '$intl hour'"; $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; } else if ($feed == Feeds::FEED_ALL) { // all articles virtual feed @@ -1660,8 +1659,6 @@ class Feeds extends Handler_Protected { if ($feed == Feeds::FEED_FRESH) $first_id_query_strategy_part = "true"; - $sanity_interval_qpart = Db::past_comparison_qpart('date_entered', '>=', 1, 'hour') . ' AND '; - $distinct_columns = str_replace("desc", "", strtolower($order_by)); $distinct_qpart = "DISTINCT ON (id, $distinct_columns)"; @@ -1695,7 +1692,7 @@ class Feeds extends Handler_Protected { $search_query_part $start_ts_query_part $since_id_part - $sanity_interval_qpart + date_entered >= NOW() - INTERVAL '1 hour' AND $first_id_query_strategy_part ORDER BY $order_by LIMIT 1"; if (!empty($_REQUEST["debug"])) { diff --git a/classes/RPC.php b/classes/RPC.php index 6ce2c12aa..8ecec41f5 100644 --- a/classes/RPC.php +++ b/classes/RPC.php @@ -438,13 +438,12 @@ class RPC extends Handler_Protected { $data["labels"] = Labels::get_all($_SESSION["uid"]); if (Config::get(Config::LOG_DESTINATION) == 'sql' && $_SESSION['access_level'] >= UserHelper::ACCESS_LEVEL_ADMIN) { - $log_interval = Db::past_comparison_qpart('created_at', '>', 1, 'hour'); $sth = $pdo->prepare("SELECT COUNT(id) AS cid FROM ttrss_error_log WHERE errno NOT IN (".E_USER_NOTICE.", ".E_USER_DEPRECATED.") AND - $log_interval AND + created_at > NOW() - INTERVAL '1 hour' AND errstr NOT LIKE '%Returning bool from comparison function is deprecated%' AND errstr NOT LIKE '%imagecreatefromstring(): Data is not in a recognized format%'"); $sth->execute(); diff --git a/classes/RSSUtils.php b/classes/RSSUtils.php index 5354ae7ba..9403cebdd 100644 --- a/classes/RSSUtils.php +++ b/classes/RSSUtils.php @@ -93,7 +93,7 @@ class RSSUtils { } if (!Config::get(Config::SINGLE_USER_MODE) && Config::get(Config::DAEMON_UPDATE_LOGIN_LIMIT) > 0) { - $login_thresh_qpart = 'AND ' . Db::past_comparison_qpart('last_login', '>=', Config::get(Config::DAEMON_UPDATE_LOGIN_LIMIT), 'day'); + $login_thresh_qpart = "AND last_login >= NOW() - INTERVAL '" . Config::get(Config::DAEMON_UPDATE_LOGIN_LIMIT) . " day'"; } else { $login_thresh_qpart = ""; } @@ -113,15 +113,10 @@ class RSSUtils { AND (last_updated = '1970-01-01 00:00:00' OR last_updated IS NULL) ))"; - // Test if feed is currently being updated by another process. - $updstart_thresh_qpart = 'AND (last_update_started IS NULL OR ' - . Db::past_comparison_qpart('last_update_started', '<', 10, 'minute') . ')'; - $query_limit = $limit ? sprintf("LIMIT %d", $limit) : ""; - // Update the least recently updated feeds first - $query_order = "ORDER BY last_updated NULLS FIRST"; - + // The 'last_update_started' check is to determine if the feed is currently being updated by another process. + // Update the least recently updated feeds first. $query = "SELECT f.feed_url, f.last_updated FROM ttrss_feeds f, ttrss_users u LEFT JOIN ttrss_user_prefs2 p ON @@ -131,8 +126,8 @@ class RSSUtils { u.access_level NOT IN (".sprintf("%d, %d", UserHelper::ACCESS_LEVEL_DISABLED, UserHelper::ACCESS_LEVEL_READONLY).") $login_thresh_qpart $update_limit_qpart - $updstart_thresh_qpart - $query_order $query_limit"; + AND (last_update_started IS NULL OR last_update_started < NOW() - INTERVAL '10 minute') + ORDER BY last_updated NULLS FIRST $query_limit"; Debug::log("base feed query: $query", Debug::LOG_EXTENDED); @@ -348,13 +343,11 @@ class RSSUtils { /** @var DiskCache $cache */ $cache = DiskCache::instance('feeds'); - $favicon_interval_qpart = Db::past_comparison_qpart('favicon_last_checked', '<', 12, 'hour'); - $feed_obj = ORM::for_table('ttrss_feeds') ->select_expr("ttrss_feeds.*, ".SUBSTRING_FOR_DATE."(last_unconditional, 1, 19) AS last_unconditional, (favicon_is_custom IS NOT TRUE AND - (favicon_last_checked IS NULL OR $favicon_interval_qpart)) AS favicon_needs_check") + (favicon_last_checked IS NULL OR favicon_last_checked < NOW() - INTERVAL '12 hour')) AS favicon_needs_check") ->find_one($feed); if ($feed_obj) { @@ -1418,8 +1411,7 @@ class RSSUtils { static function expire_error_log(): void { Debug::log("Removing old error log entries..."); $pdo = Db::pdo(); - $pdo->query('DELETE FROM ttrss_error_log - WHERE ' . Db::past_comparison_qpart('created_at', '<', 7, 'day')); + $pdo->query("DELETE FROM ttrss_error_log WHERE created_at < NOW() - INTERVAL '1 week'"); } static function expire_lock_files(): void { @@ -1647,13 +1639,11 @@ class RSSUtils { $pdo->beginTransaction(); - $interval_query = Db::past_comparison_qpart('last_successful_update', '<', Config::get(Config::DAEMON_UNSUCCESSFUL_DAYS_LIMIT), 'day') - . ' AND ' . Db::past_comparison_qpart('last_updated', '>', 1, 'day'); - - $sth = $pdo->prepare("SELECT id, title, owner_uid - FROM ttrss_feeds - WHERE update_interval != -1 AND last_successful_update IS NOT NULL AND $interval_query"); + $failing_feeds_qpart = "update_interval != -1 AND last_successful_update IS NOT NULL " + . "AND last_successful_update < NOW() - INTERVAL '" . Config::get(Config::DAEMON_UNSUCCESSFUL_DAYS_LIMIT) . " day' " + . "AND last_updated > NOW() - INTERVAL '1 day'"; + $sth = $pdo->prepare("SELECT id, title, owner_uid FROM ttrss_feeds WHERE $failing_feeds_qpart"); $sth->execute(); while ($row = $sth->fetch()) { @@ -1665,8 +1655,7 @@ class RSSUtils { clean($row["title"]), Config::get(Config::DAEMON_UNSUCCESSFUL_DAYS_LIMIT))); } - $sth = $pdo->prepare("UPDATE ttrss_feeds SET update_interval = -1 WHERE - update_interval != -1 AND last_successful_update IS NOT NULL AND $interval_query"); + $sth = $pdo->prepare("UPDATE ttrss_feeds SET update_interval = -1 WHERE $failing_feeds_qpart"); $sth->execute(); $pdo->commit(); diff --git a/update.php b/update.php index dfac5ab4c..9df6a0abe 100755 --- a/update.php +++ b/update.php @@ -33,8 +33,6 @@ } function cleanup_tags(int $days = 14, int $limit = 1000): int { - $interval_query = Db::past_comparison_qpart('e.date_updated', '<', $days, 'day'); - $tags_deleted = 0; $limit_part = 500; @@ -45,7 +43,7 @@ ->join('ttrss_user_entries', ['ue.int_id', '=', 't.post_int_id'], 'ue') ->join('ttrss_entries', ['e.id', '=', 'ue.ref_id'], 'e') ->where_not_equal('ue.tag_cache', '') - ->where_raw($interval_query) + ->where_raw("e.date_updated < NOW() - INTERVAL '$days day'") ->limit($limit_part) ->find_many();