about summary refs log tree commit homepage
path: root/lib/PublicInbox/Over.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/Over.pm')
-rw-r--r--lib/PublicInbox/Over.pm70
1 files changed, 55 insertions, 15 deletions
diff --git a/lib/PublicInbox/Over.pm b/lib/PublicInbox/Over.pm
index 19da056a..3b7d49f5 100644
--- a/lib/PublicInbox/Over.pm
+++ b/lib/PublicInbox/Over.pm
@@ -1,4 +1,4 @@
-# Copyright (C) 2018-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 
 # for XOVER, OVER in NNTP, and feeds/homepage/threads in PSGI
@@ -12,15 +12,17 @@ use DBD::SQLite;
 use PublicInbox::Smsg;
 use Compress::Zlib qw(uncompress);
 use constant DEFAULT_LIMIT => 1000;
+use List::Util (); # for max
 
 sub dbh_new {
         my ($self, $rw) = @_;
         my $f = delete $self->{filename};
-        if (!-f $f) { # SQLite defaults mode to 0644, we want 0666
+        if (!-s $f) { # SQLite defaults mode to 0644, we want 0666
                 if ($rw) {
-                        require PublicInbox::Spawn;
+                        require PublicInbox::Syscall;
+                        my ($dir) = ($f =~ m!(.+)/[^/]+\z!);
+                        PublicInbox::Syscall::nodatacow_dir($dir);
                         open my $fh, '+>>', $f or die "failed to open $f: $!";
-                        PublicInbox::Spawn::nodatacow_fd(fileno($fh));
                 } else {
                         $self->{filename} = $f; # die on stat() below:
                 }
@@ -80,7 +82,13 @@ sub dbh_close {
         }
 }
 
-sub dbh ($) { $_[0]->{dbh} //= $_[0]->dbh_new } # dbh_new may be subclassed
+sub dbh ($) {
+        my ($self) = @_;
+        $self->{dbh} // do {
+                my $dbh = $self->dbh_new; # dbh_new may be subclassed
+                $self->{dbh} = $dbh;
+        }
+}
 
 sub load_from_row ($;$) {
         my ($smsg, $cull) = @_;
@@ -106,8 +114,8 @@ sub do_get {
 }
 
 sub query_xover {
-        my ($self, $beg, $end) = @_;
-        do_get($self, <<'', {}, $beg, $end);
+        my ($self, $beg, $end, $opt) = @_;
+        do_get($self, <<'', $opt, $beg, $end);
 SELECT num,ts,ds,ddd FROM over WHERE num >= ? AND num <= ?
 ORDER BY num ASC
 
@@ -192,15 +200,22 @@ ORDER BY $sort_col DESC
                 # TODO separate strict and loose matches here once --reindex
                 # is fixed to preserve `tid' properly
                 push @$msgs, @$loose;
+
+                # we wanted to retrieve the latest loose messages; but preserve
+                # chronological ordering for threading /$INBOX/$MSGID/[tT]/
+                $sort_col eq 'ds' and
+                        @$msgs = sort { $a->{ds} <=> $b->{ds} } @$msgs;
         }
         ($nr, $msgs);
 }
 
 # strict `tid' matches, only, for thread-expanded mbox.gz search results
-# and future CLI interface
+# and lei
 # returns true if we have IDs, undef if not
 sub expand_thread {
         my ($self, $ctx) = @_;
+        # previous maxuid for LeiSavedSearch is our min:
+        my $lss_min = $ctx->{min} // 0;
         my $dbh = dbh($self);
         do {
                 defined(my $num = $ctx->{ids}->[0]) or return;
@@ -213,7 +228,7 @@ SELECT num FROM over WHERE tid = ? AND num > ?
 ORDER BY num ASC LIMIT 1000
 
                         my $xids = $dbh->selectcol_arrayref($sql, undef, $tid,
-                                                        $ctx->{prev} // 0);
+                                List::Util::max($ctx->{prev} // 0, $lss_min));
                         if (scalar(@$xids)) {
                                 $ctx->{prev} = $xids->[-1];
                                 $ctx->{xids} = $xids;
@@ -252,9 +267,12 @@ SELECT ts,ds,ddd FROM over WHERE $s
 sub get_art {
         my ($self, $num) = @_;
         # caching $sth ourselves is faster than prepare_cached
-        my $sth = $self->{-get_art} //= dbh($self)->prepare(<<'');
+        my $sth = $self->{-get_art} // do {
+                my $sth = dbh($self)->prepare(<<'');
 SELECT num,tid,ds,ts,ddd FROM over WHERE num = ? LIMIT 1
 
+                $self->{-get_art} = $sth;
+        };
         $sth->execute($num);
         my $smsg = $sth->fetchrow_hashref;
         $smsg ? load_from_row($smsg) : undef;
@@ -272,13 +290,35 @@ SELECT ibx_id,xnum,oidbin FROM xref3 WHERE docid = ? ORDER BY ibx_id,xnum ASC
         my $eidx_key_sth = $dbh->prepare_cached(<<'', undef, 1);
 SELECT eidx_key FROM inboxes WHERE ibx_id = ?
 
-        [ map {
-                my $r = $_;
+        for my $r (@$rows) {
                 $eidx_key_sth->execute($r->[0]);
                 my $eidx_key = $eidx_key_sth->fetchrow_array;
                 $eidx_key //= "missing://ibx_id=$r->[0]";
-                "$eidx_key:$r->[1]:".unpack('H*', $r->[2]);
-        } @$rows ];
+                $r = "$eidx_key:$r->[1]:".unpack('H*', $r->[2]);
+        }
+        $rows;
+}
+
+sub mid2tid {
+        my ($self, $mid) = @_;
+        my $dbh = dbh($self);
+
+        my $sth = $dbh->prepare_cached(<<'', undef, 1);
+SELECT id FROM msgid WHERE mid = ? LIMIT 1
+
+        $sth->execute($mid);
+        my $id = $sth->fetchrow_array or return;
+        $sth = $dbh->prepare_cached(<<'', undef, 1);
+SELECT num FROM id2num WHERE id = ? AND num > ?
+ORDER BY num ASC LIMIT 1
+
+        $sth->execute($id, 0);
+        my $num = $sth->fetchrow_array or return;
+        $sth = $dbh->prepare(<<'');
+SELECT tid FROM over WHERE num = ? LIMIT 1
+
+        $sth->execute($num);
+        $sth->fetchrow_array;
 }
 
 sub next_by_mid {
@@ -287,7 +327,7 @@ sub next_by_mid {
 
         unless (defined $$id) {
                 my $sth = $dbh->prepare_cached(<<'', undef, 1);
-        SELECT id FROM msgid WHERE mid = ? LIMIT 1
+SELECT id FROM msgid WHERE mid = ? LIMIT 1
 
                 $sth->execute($mid);
                 $$id = $sth->fetchrow_array;