sub add_over {
my ($self, $values) = @_;
- my ($ts, $num, $mids, $refs, $xpath, $ddd) = @$values;
+ my ($ts, $ds, $num, $mids, $refs, $xpath, $ddd) = @$values;
my $old_tid;
my $vivified = 0;
my $sid = $self->sid($xpath);
my $dbh = $self->{dbh};
my $sth = $dbh->prepare_cached(<<'');
-INSERT INTO over (num, tid, sid, ts, ddd)
-VALUES (?,?,?,?,?)
+INSERT INTO over (num, tid, sid, ts, ds, ddd)
+VALUES (?,?,?,?,?,?)
my $n = 0;
- my @v = ($num, $tid, $sid, $ts);
+ my @v = ($num, $tid, $sid, $ts, $ds);
foreach (@v) { $sth->bind_param(++$n, $_) }
$sth->bind_param(++$n, $ddd, SQL_BLOB);
$sth->execute;
tid INTEGER NOT NULL,
sid INTEGER,
ts INTEGER,
+ ds INTEGER,
ddd VARBINARY, /* doc-data-deflated */
UNIQUE (num)
)
$dbh->do('CREATE INDEX IF NOT EXISTS idx_tid ON over (tid)');
$dbh->do('CREATE INDEX IF NOT EXISTS idx_sid ON over (sid)');
$dbh->do('CREATE INDEX IF NOT EXISTS idx_ts ON over (ts)');
+ $dbh->do('CREATE INDEX IF NOT EXISTS idx_ds ON over (ds)');
$dbh->do(<<'');
CREATE TABLE IF NOT EXISTS counter (
# values for searching
use constant TS => 0; # Received: header in Unix time
-use constant YYYYMMDD => 1; # for searching in the WWW UI
+use constant YYYYMMDD => 1; # Date: header for searching in the WWW UI
+use constant DT => 2; # Date: YYYYMMDDHHMMSS
use Search::Xapian qw/:standard/;
use PublicInbox::SearchMsg;
date range as YYYYMMDD e.g. d:19931002..20101002
Open-ended ranges such as d:19931002.. and d:..20101002
are also supported
+EOF
+ 'dt:' => <<EOF,
+date-time range as YYYYMMDDhhmmss (e.g. dt:19931002011000..19931002011200)
EOF
'b:' => 'match within message body, including text attachments',
'nq:' => 'match non-quoted text within message body',
$qp->set_stemming_strategy(STEM_SOME);
$qp->add_valuerangeprocessor(
Search::Xapian::NumberValueRangeProcessor->new(YYYYMMDD, 'd:'));
+ $qp->add_valuerangeprocessor(
+ Search::Xapian::NumberValueRangeProcessor->new(DT, 'dt:'));
while (my ($name, $prefix) = each %bool_pfx_external) {
$qp->add_boolean_prefix($name, $prefix);
$smsg->{lines} = $mime->body_raw =~ tr!\n!\n!;
defined $bytes or $bytes = length($mime->as_string);
$smsg->{bytes} = $bytes;
+
add_val($doc, PublicInbox::Search::TS(), $smsg->ts);
- my $yyyymmdd = strftime('%Y%m%d', gmtime($smsg->ds));
- add_val($doc, PublicInbox::Search::YYYYMMDD, $yyyymmdd);
+ my @ds = gmtime($smsg->ds);
+ my $yyyymmdd = strftime('%Y%m%d', @ds);
+ add_val($doc, PublicInbox::Search::YYYYMMDD(), $yyyymmdd);
+ my $dt = strftime('%Y%m%d%H%M%S', @ds);
+ add_val($doc, PublicInbox::Search::DT(), $dt);
+ my @vals = ($smsg->{ts}, $smsg->{ds});
my $tg = $self->term_generator;
utf8::encode($data);
$data = compress($data);
- my @vals = ($smsg->ts, $num, $mids, $refs, $xpath, $data);
+ push @vals, $num, $mids, $refs, $xpath, $data;
$self->{over}->add_over(\@vals);
$doc->add_boolean_term('Q' . $_) foreach @$mids;
$doc->add_boolean_term('XNUM' . $num) if defined $num;
use PublicInbox::MID qw/mid_clean mid_mime/;
use PublicInbox::Address;
use PublicInbox::MsgTime qw(msg_timestamp msg_datestamp);
+use Time::Local qw(timegm);
sub new {
my ($class, $mime) = @_;
$self->cc,
$oid,
$mid0,
- $self->ds,
$self->{bytes},
$self->{lines}
);
$self->{blob},
$self->{mid},
- $self->{ds},
$self->{bytes},
$self->{lines}
) = split(/\n/, $_[1]);
my ($self) = @_;
my $doc = $self->{doc};
my $data = $doc->get_data or return;
- $self->{ts} = get_val($doc, &PublicInbox::Search::TS);
+ $self->{ts} = get_val($doc, PublicInbox::Search::TS());
+ my $dt = get_val($doc, PublicInbox::Search::DT());
+ my ($yyyy, $mon, $dd, $hh, $mm, $ss) = unpack('A4A2A2A2A2A2', $dt);
+ $self->{ds} = timegm($ss, $mm, $hh, $dd, $mon - 1, $yyyy);
utf8::decode($data);
load_from_data($self, $data);
$self;
my $ddd = compress('');
foreach my $s ('', undef) {
- $over->add_over([0, 98, [ 'a' ], [], $s, $ddd]);
- $over->add_over([0, 99, [ 'b' ], [], $s, $ddd]);
+ $over->add_over([0, 0, 98, [ 'a' ], [], $s, $ddd]);
+ $over->add_over([0, 0, 99, [ 'b' ], [], $s, $ddd]);
my $msgs = [ map { $_->{num} } @{$over->get_thread('a')} ];
is_deeply([98], $msgs,
'messages not linked by empty subject');
}
-$over->add_over([0, 98, [ 'a' ], [], 's', $ddd]);
-$over->add_over([0, 99, [ 'b' ], [], 's', $ddd]);
+$over->add_over([0, 0, 98, [ 'a' ], [], 's', $ddd]);
+$over->add_over([0, 0, 99, [ 'b' ], [], 's', $ddd]);
foreach my $mid (qw(a b)) {
my $msgs = [ map { $_->{num} } @{$over->get_thread('a')} ];
is_deeply([98, 99], $msgs, 'linked messages by subject');
}
-$over->add_over([0, 98, [ 'a' ], [], 's', $ddd]);
-$over->add_over([0, 99, [ 'b' ], ['a'], 'diff', $ddd]);
+$over->add_over([0, 0, 98, [ 'a' ], [], 's', $ddd]);
+$over->add_over([0, 0, 99, [ 'b' ], ['a'], 'diff', $ddd]);
foreach my $mid (qw(a b)) {
my $msgs = [ map { $_->{num} } @{$over->get_thread($mid)} ];
is_deeply([98, 99], $msgs, "linked messages by Message-ID: <$mid>");
# body
$res = $ro->query('goodbye');
is($res->[0]->mid, 'last@s', 'got goodbye message body');
+
+ # datestamp
+ $res = $ro->query('dt:20101002000001..20101002000001');
+ @res = filter_mids($res);
+ is_deeply(\@res, ['ghost-message@s'], 'exact Date: match works');
+ $res = $ro->query('dt:20101002000002..20101002000002');
+ is_deeply($res, [], 'exact Date: match down to the second');
}
# long message-id