bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen#include "lib.h"
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen#include "array.h"
f2f86ec77d1e4986e95990976447c2d1520a8357Timo Sirainen#include "str.h"
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen#include "seq-range-array.h"
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen#include "mail-search.h"
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen#include "fts-api-private.h"
fe3f637ef0b9544a567b54f3743cf8e3649d8d0fTimo Sirainen#include "fts-search-args.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "fts-search-serialize.h"
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen#include "fts-storage.h"
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainenstatic void
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenuid_range_to_seqs(struct fts_search_context *fctx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const ARRAY_TYPE(seq_range) *uid_range,
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen ARRAY_TYPE(seq_range) *seq_range)
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen{
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen const struct seq_range *range;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen unsigned int i, count;
c8b5a21a139992e66b4ad02adb69eaf929b3d024Timo Sirainen uint32_t seq1, seq2;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen range = array_get(uid_range, &count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (!array_is_created(seq_range))
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(seq_range, fctx->result_pool, count);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen for (i = 0; i < count; i++) {
ed4caf5f1a6ea7214b24b4d28f62eb5b8af4d6a7Timo Sirainen if (range[i].seq1 > range[i].seq2)
ed4caf5f1a6ea7214b24b4d28f62eb5b8af4d6a7Timo Sirainen continue;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mailbox_get_seq_range(fctx->box, range[i].seq1, range[i].seq2,
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen &seq1, &seq2);
c8b5a21a139992e66b4ad02adb69eaf929b3d024Timo Sirainen if (seq1 != 0)
c8b5a21a139992e66b4ad02adb69eaf929b3d024Timo Sirainen seq_range_array_add_range(seq_range, seq1, seq2);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen }
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen}
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int fts_search_lookup_level_single(struct fts_search_context *fctx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_search_arg *args,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen bool and_args)
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen{
117fb8c00336dc54bab9cfa547249df7a4970611Timo Sirainen enum fts_lookup_flags flags = fctx->flags |
117fb8c00336dc54bab9cfa547249df7a4970611Timo Sirainen (and_args ? FTS_LOOKUP_FLAG_AND_ARGS : 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_search_level *level;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_result result;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&result);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&result.definite_uids, fctx->result_pool, 32);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&result.maybe_uids, fctx->result_pool, 32);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&result.scores, fctx->result_pool, 32);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_search_args_reset(args, TRUE);
117fb8c00336dc54bab9cfa547249df7a4970611Timo Sirainen if (fts_backend_lookup(fctx->backend, fctx->box, args, flags,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen &result) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen level = array_append_space(&fctx->levels);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen level->args_matches = buffer_create_dynamic(fctx->result_pool, 16);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_serialize(level->args_matches, args);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen uid_range_to_seqs(fctx, &result.definite_uids, &level->definite_seqs);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen uid_range_to_seqs(fctx, &result.maybe_uids, &level->maybe_seqs);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen level->score_map = result.scores;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen}
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainenlevel_scores_add_vuids(struct mailbox *box,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_search_level *level, struct fts_result *br)
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct fts_score_map *scores;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int i, count;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ARRAY_TYPE(seq_range) backend_uids;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ARRAY_TYPE(uint32_t) vuids_arr;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const uint32_t *vuids;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_score_map *score;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen scores = array_get(&br->scores, &count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen t_array_init(&vuids_arr, count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen t_array_init(&backend_uids, 64);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (i = 0; i < count; i++)
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&backend_uids, scores[i].uid);
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen box->virtual_vfuncs->get_virtual_uid_map(box, br->box,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen &backend_uids, &vuids_arr);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(array_count(&vuids_arr) == array_count(&br->scores));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen vuids = array_get(&vuids_arr, &count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (i = 0; i < count; i++) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen score = array_append_space(&level->score_map);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen score->uid = vuids[i];
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen score->score = scores[i].score;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenmailbox_cmp_fts_backend(struct mailbox *const *m1, struct mailbox *const *m2)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_backend *b1, *b2;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen b1 = fts_mailbox_backend(*m1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen b2 = fts_mailbox_backend(*m2);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (b1 < b2)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (b1 > b2)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenmulti_add_lookup_result(struct fts_search_context *fctx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_search_level *level,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_search_arg *args,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_multi_result *result)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ARRAY_TYPE(seq_range) vuids;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen size_t orig_size;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int i;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen orig_size = level->args_matches->used;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_serialize(level->args_matches, args);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (orig_size > 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (level->args_matches->used != orig_size * 2 ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen memcmp(level->args_matches->data,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen CONST_PTR_OFFSET(level->args_matches->data,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen orig_size), orig_size) != 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_panic("incompatible fts backends for namespaces");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen buffer_set_used_size(level->args_matches, orig_size);
de11cf486e0d0448537b1b5d546496ab85e7cda8Timo Sirainen }
d798962a54c5cda054d57a0cfc7e5f47dfa20f6eTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen t_array_init(&vuids, 64);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (i = 0; result->box_results[i].box != NULL; i++) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_result *br = &result->box_results[i];
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_clear(&vuids);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (array_is_created(&br->definite_uids)) {
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen fctx->box->virtual_vfuncs->get_virtual_uids(fctx->box,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen br->box, &br->definite_uids, &vuids);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen uid_range_to_seqs(fctx, &vuids, &level->definite_seqs);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_clear(&vuids);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (array_is_created(&br->maybe_uids)) {
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen fctx->box->virtual_vfuncs->get_virtual_uids(fctx->box,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen br->box, &br->maybe_uids, &vuids);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen uid_range_to_seqs(fctx, &vuids, &level->maybe_seqs);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (array_is_created(&br->scores))
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen level_scores_add_vuids(fctx->box, level, br);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
d798962a54c5cda054d57a0cfc7e5f47dfa20f6eTimo Sirainen return 0;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen}
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int fts_search_lookup_level_multi(struct fts_search_context *fctx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_search_arg *args,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen bool and_args)
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen{
117fb8c00336dc54bab9cfa547249df7a4970611Timo Sirainen enum fts_lookup_flags flags = fctx->flags |
117fb8c00336dc54bab9cfa547249df7a4970611Timo Sirainen (and_args ? FTS_LOOKUP_FLAG_AND_ARGS : 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ARRAY_TYPE(mailboxes) mailboxes_arr, tmp_mailboxes;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mailbox *const *mailboxes;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_backend *backend;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_search_level *level;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_multi_result result;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int i, j, mailbox_count;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&mailboxes_arr, fctx->result_pool, 8);
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen fctx->box->virtual_vfuncs->get_virtual_backend_boxes(fctx->box,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen &mailboxes_arr, TRUE);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_sort(&mailboxes_arr, mailbox_cmp_fts_backend);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&result);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen result.pool = fctx->result_pool;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen level = array_append_space(&fctx->levels);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen level->args_matches = buffer_create_dynamic(fctx->result_pool, 16);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&level->score_map, fctx->result_pool, 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mailboxes = array_get(&mailboxes_arr, &mailbox_count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen t_array_init(&tmp_mailboxes, mailbox_count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (i = 0; i < mailbox_count; i = j) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_clear(&tmp_mailboxes);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(&tmp_mailboxes, &mailboxes[i], 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen backend = fts_mailbox_backend(mailboxes[i]);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (j = i + 1; j < mailbox_count; j++) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (fts_mailbox_backend(mailboxes[j]) != backend)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen break;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(&tmp_mailboxes, &mailboxes[j], 1);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&tmp_mailboxes);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_search_args_reset(args, TRUE);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (fts_backend_lookup_multi(backend,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_idx(&tmp_mailboxes, 0),
117fb8c00336dc54bab9cfa547249df7a4970611Timo Sirainen args, flags, &result) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (multi_add_lookup_result(fctx, level, args, &result) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int fts_search_lookup_level(struct fts_search_context *fctx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_search_arg *args,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen bool and_args)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen int ret;
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen T_BEGIN {
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen ret = !fctx->virtual_mailbox ?
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen fts_search_lookup_level_single(fctx, args, and_args) :
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen fts_search_lookup_level_multi(fctx, args, and_args);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } T_END;
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen if (ret < 0)
d05e9a7a1c48d6a20e48c034be1f50f59becb377Timo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (; args != NULL; args = args->next) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (args->type != SEARCH_OR && args->type != SEARCH_SUB)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen continue;
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (fts_search_lookup_level(fctx, args->value.subargs,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen args->type == SEARCH_SUB) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
809923ba26218971792182ae8894936f9ac99364Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenfts_search_merge_scores_and(ARRAY_TYPE(fts_score_map) *dest,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const ARRAY_TYPE(fts_score_map) *src)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct fts_score_map *dest_map;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct fts_score_map *src_map;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int desti, srci, dest_count, src_count;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen dest_map = array_get_modifiable(dest, &dest_count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen src_map = array_get(src, &src_count);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* arg_scores are summed to current scores. we could drop UIDs that
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen don't exist in both, but that's just extra work so don't bother */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (desti = srci = 0; desti < dest_count && srci < src_count;) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (dest_map[desti].uid < src_map[srci].uid)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen desti++;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen else if (dest_map[desti].uid > src_map[srci].uid)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen srci++;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (dest_map[desti].score < src_map[srci].score)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen dest_map[desti].score = src_map[srci].score;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen desti++; srci++;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen }
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen}
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenfts_search_merge_scores_or(ARRAY_TYPE(fts_score_map) *dest,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const ARRAY_TYPE(fts_score_map) *src)
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ARRAY_TYPE(fts_score_map) src2;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct fts_score_map *src_map, *src2_map;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int srci, src2i, src_count, src2_count;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen t_array_init(&src2, array_count(dest));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append_array(&src2, dest);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_clear(dest);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen src_map = array_get(src, &src_count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen src2_map = array_get(&src2, &src2_count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* add any missing UIDs to current scores. if any existing UIDs have
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen lower scores than in arg_scores, increase them. */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (srci = src2i = 0; srci < src_count || src2i < src2_count;) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (src2i == src2_count ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen src_map[srci].uid < src2_map[src2i].uid) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(dest, &src_map[srci], 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen srci++;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else if (srci == src_count ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen src_map[srci].uid > src2_map[src2i].uid) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(dest, &src2_map[src2i], 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen src2i++;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(src_map[srci].uid == src2_map[src2i].uid);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (src_map[srci].score > src2_map[src2i].score)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(dest, &src_map[srci], 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen else
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(dest, &src2_map[src2i], 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen srci++; src2i++;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen}
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainenstatic void
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenfts_search_merge_scores_level(struct fts_search_context *fctx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_search_arg *args, unsigned int *idx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen bool and_args, ARRAY_TYPE(fts_score_map) *scores)
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct fts_search_level *level;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ARRAY_TYPE(fts_score_map) arg_scores;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(array_count(scores) == 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /*
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen The (simplified) args can look like:
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen A and B and (C or D) and (E or F) and ...
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen A or B or (C and D) or (E and F) or ...
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen The A op B part's scores are in level->scores. The child args'
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen scores are in the sub levels' scores.
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen level = array_idx(&fctx->levels, *idx);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append_array(scores, &level->score_map);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen t_array_init(&arg_scores, 64);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen for (; args != NULL; args = args->next) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (args->type != SEARCH_OR && args->type != SEARCH_SUB)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen continue;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen *idx += 1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_clear(&arg_scores);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_merge_scores_level(fctx, args->value.subargs, idx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen args->type == SEARCH_OR,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen &arg_scores);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (and_args)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_merge_scores_and(scores, &arg_scores);
212fbaebeda9ef9ea9b8e10e451cd59fa726cd6eTimo Sirainen else
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_merge_scores_or(scores, &arg_scores);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen }
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen}
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void fts_search_merge_scores(struct fts_search_context *fctx)
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int idx = 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_merge_scores_level(fctx, fctx->args->args, &idx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen TRUE, &fctx->scores->score_map);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid fts_search_lookup(struct fts_search_context *fctx)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen uint32_t last_uid, seq1, seq2;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(array_count(&fctx->levels) == 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(fctx->args->simplified);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (fts_backend_refresh(fctx->backend) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (fts_backend_get_last_uid(fctx->backend, fctx->box, &last_uid) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mailbox_get_seq_range(fctx->box, last_uid+1, (uint32_t)-1,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen &seq1, &seq2);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fctx->first_unindexed_seq = seq1 != 0 ? seq1 : (uint32_t)-1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
fe3f637ef0b9544a567b54f3743cf8e3649d8d0fTimo Sirainen if ((fctx->backend->flags & FTS_BACKEND_FLAG_TOKENIZED_INPUT) != 0) {
fe3f637ef0b9544a567b54f3743cf8e3649d8d0fTimo Sirainen if (fts_search_args_expand(fctx->backend, fctx->args) < 0)
fe3f637ef0b9544a567b54f3743cf8e3649d8d0fTimo Sirainen return;
fe3f637ef0b9544a567b54f3743cf8e3649d8d0fTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_serialize(fctx->orig_matches, fctx->args->args);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (fts_search_lookup_level(fctx, fctx->args->args, TRUE) == 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fctx->fts_lookup_success = TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_merge_scores(fctx);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fts_search_deserialize(fctx->args->args, fctx->orig_matches);
b7fdf4fe23801de680e0be5aca0596a3c9ea3f8fTimo Sirainen fts_backend_lookup_done(fctx->backend);
67f1723e1685b4bf73c1cca0a1e08a0a87ffd410Timo Sirainen}