• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 2085

01 Mar 2024 12:26PM UTC coverage: 90.926% (-0.001%) from 90.927%
2085

push

Evergreen

jedelbo
Avoid doing unneeded logger work in Replication

Most of the replication log statements do some work including memory
allocations which are then thrown away if the log level it too high, so always
check the log level first. A few places don't actually benefit from this, but
it's easier to consistently check the log level every time.

93986 of 173116 branches covered (54.29%)

63 of 100 new or added lines in 2 files covered. (63.0%)

114 existing lines in 17 files now uncovered.

238379 of 262169 relevant lines covered (90.93%)

6007877.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.18
/src/realm/table_view.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include <realm/table_view.hpp>
20
#include <realm/column_integer.hpp>
21
#include <realm/index_string.hpp>
22
#include <realm/transaction.hpp>
23

24
#include <unordered_set>
25

26
using namespace realm;
27

28
TableView::TableView(TableView& src, Transaction* tr, PayloadPolicy policy_mode)
29
    : m_source_column_key(src.m_source_column_key)
30
{
62,430✔
31
    bool was_in_sync = src.is_in_sync();
62,430✔
32
    if (src.m_query)
62,430✔
33
        m_query = Query(*src.m_query, tr, policy_mode);
61,824✔
34
    m_table = tr->import_copy_of(src.m_table);
62,430✔
35

31,422✔
36
    if (policy_mode == PayloadPolicy::Stay)
62,430✔
37
        was_in_sync = false;
96✔
38

31,422✔
39
    VersionID src_version =
62,430✔
40
        dynamic_cast<Transaction*>(src.m_table->get_parent_group())->get_version_of_current_transaction();
62,430✔
41
    if (src_version != tr->get_version_of_current_transaction())
62,430✔
42
        was_in_sync = false;
18✔
43

31,422✔
44
    m_table = tr->import_copy_of(src.m_table);
62,430✔
45
    m_collection_source = tr->import_copy_of(src.m_collection_source);
62,430✔
46
    if (src.m_source_column_key) {
62,430✔
47
        m_linked_obj = tr->import_copy_of(src.m_linked_obj);
606✔
48
    }
606✔
49

31,422✔
50
    if (was_in_sync)
62,430✔
51
        get_dependencies(m_last_seen_versions);
62,310✔
52

31,422✔
53
    // don't use methods which throw after this point...or m_table_view_key_values will leak
31,422✔
54
    if (policy_mode == PayloadPolicy::Copy && src.m_key_values.is_attached()) {
62,430✔
55
        m_key_values = src.m_key_values;
702✔
56
    }
702✔
57
    else if (policy_mode == PayloadPolicy::Move && src.m_key_values.is_attached())
61,728✔
58
        // Requires that 'src' is a writable object
31,023✔
59
        m_key_values = std::move(src.m_key_values);
61,632✔
60
    else {
96✔
61
        m_key_values.create();
96✔
62
    }
96✔
63
    if (policy_mode == PayloadPolicy::Move) {
62,430✔
64
        src.m_last_seen_versions.clear();
61,632✔
65
    }
61,632✔
66
    m_descriptor_ordering = src.m_descriptor_ordering;
62,430✔
67
    m_limit = src.m_limit;
62,430✔
68
}
62,430✔
69

70
// Aggregates ----------------------------------------------------
71

72
template <typename T, Action AggregateOpType>
73
struct Aggregator {
74
};
75

76
template <typename T>
77
struct Aggregator<T, act_Sum> {
78
    using AggType = typename aggregate_operations::Sum<typename util::RemoveOptional<T>::type>;
79
};
80

81
template <typename T>
82
struct Aggregator<T, act_Average> {
83
    using AggType = typename aggregate_operations::Average<typename util::RemoveOptional<T>::type>;
84
};
85

86
template <typename T>
87
struct Aggregator<T, act_Min> {
88
    using AggType = typename aggregate_operations::Minimum<typename util::RemoveOptional<T>::type>;
89
};
90

91
template <typename T>
92
struct Aggregator<T, act_Max> {
93
    using AggType = typename aggregate_operations::Maximum<typename util::RemoveOptional<T>::type>;
94
};
95

96
template <Action action, typename T>
97
Mixed TableView::aggregate(ColKey column_key, size_t* result_count, ObjKey* return_key) const
98
{
4,230✔
99
    static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Average);
4,230✔
100
    REALM_ASSERT(m_table->valid_column(column_key));
4,230!
101

2,115✔
102
    size_t non_nulls = 0;
4,230✔
103
    typename Aggregator<T, action>::AggType agg;
4,230✔
104
    ObjKey last_accumulated_key = null_key;
4,230✔
105
    for (size_t tv_index = 0; tv_index < m_key_values.size(); ++tv_index) {
57,828!
106
        ObjKey key(get_key(tv_index));
53,598✔
107

26,364✔
108
        // skip detached references:
26,364✔
109
        if (key == realm::null_key)
53,598!
110
            continue;
×
111

26,364✔
112
        const Obj obj = m_table->try_get_object(key);
53,598✔
113
        // aggregation must be robust in the face of stale keys:
26,364✔
114
        if (!obj.is_valid())
53,598!
115
            continue;
24✔
116

26,352✔
117
        if (obj.is_null(column_key))
53,574!
118
            continue;
7,968✔
119

22,518✔
120
        auto v = obj.get<T>(column_key);
45,606✔
121
        if (agg.accumulate(v)) {
45,606!
122
            ++non_nulls;
30,993✔
123
            if constexpr (action == act_Min || action == act_Max) {
30,993✔
124
                last_accumulated_key = key;
15,141✔
125
            }
15,141✔
126
        }
30,993✔
127
    }
45,606✔
128

2,115✔
129
    if (result_count)
4,230!
130
        *result_count = non_nulls;
696✔
131

2,115✔
132
    if constexpr (action == act_Max || action == act_Min) {
4,230✔
133
        if (return_key) {
2,532!
134
            *return_key = last_accumulated_key;
2,040✔
135
        }
2,040✔
136
    }
2,532✔
137
    else {
1,698✔
138
        static_cast<void>(last_accumulated_key);
1,698✔
139
        static_cast<void>(return_key);
1,698✔
140
    }
1,698✔
141

2,115✔
142
    if (!agg.is_null()) {
4,230!
143
        return agg.result();
3,306✔
144
    }
3,306✔
145
    if (action == act_Sum) {
924✔
146
        if (std::is_same_v<T, Mixed>) {
×
147
            return Decimal128{0};
×
148
        }
×
149
        return T{};
×
150
    }
×
151
    return Mixed();
924✔
152
}
924✔
153

154
template <typename T>
155
size_t TableView::aggregate_count(ColKey column_key, T count_target) const
156
{
48✔
157
    REALM_ASSERT(m_table->valid_column(column_key));
48!
158

24✔
159
    if ((m_key_values.size()) == 0) {
48!
160
        return {};
×
161
    }
×
162

24✔
163
    size_t cnt = 0;
48✔
164
    for (size_t tv_index = 0; tv_index < m_key_values.size(); ++tv_index) {
240!
165
        ObjKey key(get_key(tv_index));
192✔
166

96✔
167
        // skip detached references:
96✔
168
        if (key == realm::null_key)
192!
169
            continue;
×
170

96✔
171
        const Obj obj = m_table->try_get_object(key);
192✔
172
        if (!obj.is_valid())
192!
173
            continue;
×
174

96✔
175
        auto v = obj.get<T>(column_key);
192✔
176
        if (v == count_target) {
192!
177
            cnt++;
102✔
178
        }
102✔
179
    }
192✔
180

24✔
181
    return cnt;
48✔
182
}
48✔
183

184
// Count
185
size_t TableView::count_int(ColKey column_key, int64_t target) const
186
{
12✔
187
    if (m_table->is_nullable(column_key))
12✔
188
        return aggregate_count<util::Optional<int64_t>>(column_key, target);
×
189
    else
12✔
190
        return aggregate_count<int64_t>(column_key, target);
12✔
191
}
12✔
192
size_t TableView::count_float(ColKey column_key, float target) const
193
{
12✔
194
    return aggregate_count<float>(column_key, target);
12✔
195
}
12✔
196
size_t TableView::count_double(ColKey column_key, double target) const
197
{
12✔
198
    return aggregate_count<double>(column_key, target);
12✔
199
}
12✔
200
size_t TableView::count_timestamp(ColKey column_key, Timestamp target) const
201
{
12✔
202
    return aggregate_count<Timestamp>(column_key, target);
12✔
203
}
12✔
204
size_t TableView::count_decimal(ColKey column_key, Decimal128 target) const
205
{
×
206
    return aggregate_count<Decimal128>(column_key, target);
×
207
}
×
208
size_t TableView::count_mixed(ColKey column_key, Mixed target) const
209
{
×
210
    return aggregate_count<Mixed>(column_key, target);
×
211
}
×
212

213
template <Action action>
214
std::optional<Mixed> TableView::aggregate(ColKey column_key, size_t* count, ObjKey* return_key) const
215
{
4,422✔
216
    static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Average);
4,422✔
217
    m_table->check_column(column_key);
4,422✔
218
    if (column_key.is_collection()) {
4,422✔
219
        return std::nullopt;
48✔
220
    }
48✔
221

2,187✔
222
    switch (column_key.get_type()) {
4,374✔
223
        case col_type_Int:
1,596✔
224
            if (m_table->is_nullable(column_key))
1,596✔
225
                return aggregate<action, util::Optional<int64_t>>(column_key, count, return_key);
1,470✔
226
            return aggregate<action, int64_t>(column_key, count, return_key);
126✔
227
        case col_type_Float:
1,506✔
228
            return aggregate<action, float>(column_key, count, return_key);
1,506✔
229
        case col_type_Double:
342✔
230
            return aggregate<action, double>(column_key, count, return_key);
342✔
231
        case col_type_Timestamp:
99✔
232
            if constexpr (action == act_Min || action == act_Max) {
858✔
233
                return aggregate<action, Timestamp>(column_key, count, return_key);
786✔
234
            }
786✔
235
            break;
×
236
        case col_type_Decimal:
✔
237
            return aggregate<action, Decimal128>(column_key, count, return_key);
×
238
        case col_type_Mixed:
✔
239
            return aggregate<action, Mixed>(column_key, count, return_key);
×
240
        default:
✔
241
            break;
×
242
    }
72✔
243
    return util::none;
72✔
244
}
72✔
245

246
util::Optional<Mixed> TableView::min(ColKey column_key, ObjKey* return_key) const
247
{
1,290✔
248
    return aggregate<act_Min>(column_key, nullptr, return_key);
1,290✔
249
}
1,290✔
250

251
util::Optional<Mixed> TableView::max(ColKey column_key, ObjKey* return_key) const
252
{
1,302✔
253
    return aggregate<act_Max>(column_key, nullptr, return_key);
1,302✔
254
}
1,302✔
255

256
util::Optional<Mixed> TableView::sum(ColKey column_key) const
257
{
900✔
258
    return aggregate<act_Sum>(column_key, nullptr, nullptr);
900✔
259
}
900✔
260

261
util::Optional<Mixed> TableView::avg(ColKey column_key, size_t* value_count) const
262
{
930✔
263
    return aggregate<act_Average>(column_key, value_count, nullptr);
930✔
264
}
930✔
265

266
void TableView::to_json(std::ostream& out, JSONOutputMode mode) const
267
{
36✔
268
    // Represent table as list of objects
18✔
269
    out << "[";
36✔
270

18✔
271
    const size_t row_count = size();
36✔
272
    bool first = true;
36✔
273
    for (size_t r = 0; r < row_count; ++r) {
468✔
274
        if (ObjKey key = get_key(r)) {
432✔
275
            if (first) {
432✔
276
                first = false;
36✔
277
            }
36✔
278
            else {
396✔
279
                out << ",";
396✔
280
            }
396✔
281
            m_table->get_object(key).to_json(out, mode);
432✔
282
        }
432✔
283
    }
432✔
284

18✔
285
    out << "]";
36✔
286
}
36✔
287

288
bool TableView::depends_on_deleted_object() const
289
{
42✔
290
    if (m_collection_source) {
42✔
291
        return !m_collection_source->get_owning_obj().is_valid();
12✔
292
    }
12✔
293

15✔
294
    if (m_source_column_key && !m_linked_obj.is_valid()) {
30✔
295
        return true;
12✔
296
    }
12✔
297
    else if (m_query && m_query->m_source_table_view) {
18✔
298
        return m_query->m_source_table_view->depends_on_deleted_object();
6✔
299
    }
6✔
300
    return false;
12✔
301
}
12✔
302

303
void TableView::get_dependencies(TableVersions& ret) const
304
{
1,813,587✔
305
    auto table = m_table ? m_table.unchecked_ptr() : nullptr;
2,148,455,092✔
306
    if (m_source_column_key && m_linked_obj) {
1,813,587✔
307
        // m_source_column_key is set when this TableView was created by Table::get_backlink_view().
1,056✔
308
        if (auto linked_table = m_linked_obj.get_table()) {
2,112✔
309
            ret.emplace_back(linked_table->get_key(), linked_table->get_content_version());
2,112✔
310
        }
2,112✔
311
    }
2,112✔
312
    else if (m_query) {
1,907,910✔
313
        m_query->get_outside_versions(ret);
1,903,731✔
314
    }
1,903,731✔
315
    else {
2,147,487,826✔
316
        // This TableView was created by Table::get_distinct_view() or get_sorted_view() on collections
2,147,483,647✔
317
        ret.emplace_back(table->get_key(), table->get_content_version());
2,147,487,826✔
318
    }
2,147,487,826✔
319

835,719✔
320
    // Finally add dependencies from sort/distinct
835,719✔
321
    if (table) {
1,927,032✔
322
        m_descriptor_ordering.get_versions(table->get_parent_group(), ret);
1,925,613✔
323
    }
1,925,613✔
324
}
1,813,587✔
325

326
bool TableView::is_in_sync() const
327
{
260,946✔
328
    return m_table && !has_changed();
260,946✔
329
}
260,946✔
330

331
void TableView::sync_if_needed() const
332
{
150,054✔
333
    if (!is_in_sync()) {
150,054✔
334
        // FIXME: Is this a reasonable handling of constness?
27,777✔
335
        const_cast<TableView*>(this)->do_sync();
55,497✔
336
    }
55,497✔
337
}
150,054✔
338

339
void TableView::update_query(const Query& q)
340
{
12✔
341
    REALM_ASSERT(m_query);
12✔
342
    REALM_ASSERT(m_query->m_table);
12✔
343
    REALM_ASSERT(m_query->m_table == q.m_table);
12✔
344

6✔
345
    m_query = q;
12✔
346
    do_sync();
12✔
347
}
12✔
348

349
void TableView::clear()
350
{
5,715✔
351
    m_table.check();
5,715✔
352

2,859✔
353
    // If distinct is applied then removing an object may leave us out of sync
2,859✔
354
    // if there's another object with the same value in the distinct column
2,859✔
355
    // as the removed object
2,859✔
356
    bool sync_to_keep =
5,715✔
357
        m_last_seen_versions == get_dependency_versions() && !m_descriptor_ordering.will_apply_distinct();
5,715✔
358

2,859✔
359
    // Remove all invalid keys
2,859✔
360
    auto it = std::remove_if(m_key_values.begin(), m_key_values.end(), [this](const ObjKey& key) {
2,511,627✔
361
        return !m_table->is_valid(key);
2,511,627✔
362
    });
2,511,627✔
363
    m_key_values.erase(it, m_key_values.end());
5,715✔
364

2,859✔
365
    _impl::TableFriend::batch_erase_objects(*get_parent(), m_key_values); // Throws
5,715✔
366

2,859✔
367
    // It is important to not accidentally bring us in sync, if we were
2,859✔
368
    // not in sync to start with:
2,859✔
369
    if (sync_to_keep)
5,715✔
370
        m_last_seen_versions = get_dependency_versions();
5,697✔
371
}
5,715✔
372

373
void TableView::distinct(ColKey column)
374
{
144✔
375
    distinct(DistinctDescriptor({{column}}));
144✔
376
}
144✔
377

378
/// Remove rows that are duplicated with respect to the column set passed as argument.
379
/// Will keep original sorting order so that you can both have a distinct and sorted view.
380
void TableView::distinct(DistinctDescriptor columns)
381
{
432✔
382
    m_descriptor_ordering.append_distinct(std::move(columns));
432✔
383
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
432✔
384

216✔
385
    do_sync();
432✔
386
}
432✔
387

388
void TableView::limit(LimitDescriptor lim)
389
{
12✔
390
    m_descriptor_ordering.append_limit(std::move(lim));
12✔
391
    do_sync();
12✔
392
}
12✔
393

394
void TableView::filter(FilterDescriptor filter)
395
{
12✔
396
    m_descriptor_ordering.append_filter(std::move(filter));
12✔
397
    do_sync();
12✔
398
}
12✔
399

400
void TableView::apply_descriptor_ordering(const DescriptorOrdering& new_ordering)
401
{
44,520✔
402
    m_descriptor_ordering = new_ordering;
44,520✔
403
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
44,520✔
404

22,239✔
405
    do_sync();
44,520✔
406
}
44,520✔
407

408
std::string TableView::get_descriptor_ordering_description() const
409
{
18✔
410
    return m_descriptor_ordering.get_description(m_table);
18✔
411
}
18✔
412

413
// Sort according to one column
414
void TableView::sort(ColKey column, bool ascending)
415
{
438✔
416
    sort(SortDescriptor({{column}}, {ascending}));
438✔
417
}
438✔
418

419
// Sort according to multiple columns, user specified order on each column
420
void TableView::sort(SortDescriptor order)
421
{
1,008✔
422
    m_descriptor_ordering.append_sort(std::move(order), SortDescriptor::MergeMode::prepend);
1,008✔
423
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
1,008✔
424

504✔
425
    apply_descriptors(m_descriptor_ordering);
1,008✔
426
}
1,008✔
427

428

429
void TableView::do_sync()
430
{
1,471,041✔
431
    util::CriticalSection cs(m_race_detector);
1,471,041✔
432
    // This TableView can be "born" from 4 different sources:
693,588✔
433
    // - LinkView
693,588✔
434
    // - Query::find_all()
693,588✔
435
    // - Table::get_distinct_view()
693,588✔
436
    // - Table::get_backlink_view()
693,588✔
437
    // Here we sync with the respective source.
693,588✔
438
    m_last_seen_versions.clear();
1,471,041✔
439

693,588✔
440
    if (m_collection_source) {
1,471,041✔
441
        m_key_values.clear();
102✔
442
        auto sz = m_collection_source->size();
102✔
443
        for (size_t i = 0; i < sz; i++) {
330✔
444
            m_key_values.add(m_collection_source->get_key(i));
228✔
445
        }
228✔
446
    }
102✔
447
    else if (m_source_column_key) {
1,470,939✔
448
        m_key_values.clear();
756✔
449
        if (m_table && m_linked_obj.is_valid()) {
756✔
450
            if (m_table->valid_column(m_source_column_key)) { // return empty result, if column has been removed
744✔
451
                ColKey backlink_col = m_table->get_opposite_column(m_source_column_key);
738✔
452
                REALM_ASSERT(backlink_col);
738✔
453
                auto backlinks = m_linked_obj.get_all_backlinks(backlink_col);
738✔
454
                for (auto k : backlinks) {
723✔
455
                    m_key_values.add(k);
708✔
456
                }
708✔
457
            }
738✔
458
        }
744✔
459
    }
756✔
460
    // FIXME: Unimplemented for link to a column
693,159✔
461
    else {
1,470,183✔
462
        REALM_ASSERT(m_query);
1,470,183✔
463
        m_query->m_table.check();
1,470,183✔
464

693,159✔
465
        // valid query, so clear earlier results and reexecute it.
693,159✔
466
        if (m_key_values.is_attached())
1,470,183✔
467
            m_key_values.clear();
1,487,610✔
468
        else
2,147,492,698✔
469
            m_key_values.create();
2,147,492,698✔
470

693,159✔
471
        if (m_query->m_view)
1,470,183✔
472
            m_query->m_view->sync_if_needed();
1,101✔
473
        size_t limit = m_limit;
1,470,183✔
474
        if (!m_descriptor_ordering.is_empty()) {
1,470,183✔
475
            auto type = m_descriptor_ordering[0]->get_type();
36,306✔
476
            if (type == DescriptorType::Limit) {
36,306✔
477
                size_t l = static_cast<const LimitDescriptor*>(m_descriptor_ordering[0])->get_limit();
138✔
478
                if (l < limit)
138✔
479
                    limit = l;
138✔
480
            }
138✔
481
        }
36,306✔
482
        QueryStateFindAll<std::vector<ObjKey>> st(m_key_values, limit);
1,470,183✔
483
        m_query->do_find_all(st);
1,470,183✔
484
    }
1,470,183✔
485

693,588✔
486
    apply_descriptors(m_descriptor_ordering);
1,471,041✔
487

693,588✔
488
    get_dependencies(m_last_seen_versions);
1,471,041✔
489
}
1,471,041✔
490

491
void TableView::apply_descriptors(const DescriptorOrdering& ordering)
492
{
1,591,035✔
493
    if (ordering.is_empty())
1,591,035✔
494
        return;
1,596,717✔
495
    size_t sz = size();
2,147,505,706✔
496
    if (sz == 0)
2,147,505,706✔
497
        return;
18,027✔
498

2,147,483,647✔
499
    // Gather the current rows into a container we can use std algorithms on
2,147,483,647✔
500
    size_t detached_ref_count = 0;
2,147,496,700✔
501
    BaseDescriptor::IndexPairs index_pairs;
2,147,496,700✔
502
    bool using_indexpairs = false;
2,147,496,700✔
503

2,147,483,647✔
504
    auto apply_indexpairs = [&] {
2,147,493,217✔
505
        m_key_values.clear();
19,143✔
506
        for (auto& pair : index_pairs) {
183,450✔
507
            m_key_values.add(pair.key_for_object);
183,450✔
508
        }
183,450✔
509
        for (size_t t = 0; t < detached_ref_count; ++t)
19,143✔
510
            m_key_values.add(null_key);
×
511
        using_indexpairs = false;
19,143✔
512
    };
19,143✔
513

2,147,483,647✔
514
    auto use_indexpairs = [&] {
2,147,493,229✔
515
        index_pairs.reserve(sz);
19,167✔
516
        index_pairs.clear();
19,167✔
517
        // always put any detached refs at the end of the sort
9,585✔
518
        // FIXME: reconsider if this is the right thing to do
9,585✔
519
        // FIXME: consider specialized implementations in derived classes
9,585✔
520
        // (handling detached refs is not required in linkviews)
9,585✔
521
        for (size_t t = 0; t < sz; t++) {
264,939✔
522
            ObjKey key = get_key(t);
245,772✔
523
            if (m_table->is_valid(key)) {
245,772✔
524
                index_pairs.emplace_back(key, t);
245,772✔
525
            }
245,772✔
UNCOV
526
            else
×
UNCOV
527
                ++detached_ref_count;
×
528
        }
245,772✔
529
        using_indexpairs = true;
19,167✔
530
    };
19,167✔
531

2,147,483,647✔
532
    const int num_descriptors = int(ordering.size());
2,147,496,700✔
533
    for (int desc_ndx = 0; desc_ndx < num_descriptors; ++desc_ndx) {
2,147,507,908✔
534
        const BaseDescriptor* base_descr = ordering[desc_ndx];
22,425✔
535
        const BaseDescriptor* next = ((desc_ndx + 1) < num_descriptors) ? ordering[desc_ndx + 1] : nullptr;
20,847✔
536

11,217✔
537
        // Some descriptors, like Sort and Distinct, needs us to gather the current rows
11,217✔
538
        // into a container we can use std algorithms on
11,217✔
539
        if (base_descr->need_indexpair()) {
22,425✔
540
            if (!using_indexpairs) {
19,773✔
541
                use_indexpairs();
19,167✔
542
            }
19,167✔
543

9,888✔
544
            BaseDescriptor::Sorter predicate = base_descr->sorter(*m_table, index_pairs);
19,773✔
545

9,888✔
546
            // Sorting can be specified by multiple columns, so that if two entries in the first column are
9,888✔
547
            // identical, then the rows are ordered according to the second column, and so forth. For the
9,888✔
548
            // first column, we cache all the payload of fields of the view in a std::vector<Mixed>
9,888✔
549
            predicate.cache_first_column(index_pairs);
19,773✔
550

9,888✔
551
            base_descr->execute(index_pairs, predicate, next);
19,773✔
552
        }
19,773✔
553
        else {
2,652✔
554
            if (using_indexpairs) {
2,652✔
555
                apply_indexpairs();
2,424✔
556
            }
2,424✔
557
            base_descr->execute(*m_table, m_key_values, next);
2,652✔
558
            sz = size();
2,652✔
559
        }
2,652✔
560
    }
22,425✔
561
    // Apply the results
2,147,483,647✔
562
    if (using_indexpairs) {
2,147,496,700✔
563
        apply_indexpairs();
16,719✔
564
    }
16,719✔
565
}
2,147,496,700✔
566

567
bool TableView::is_in_table_order() const
568
{
3,342✔
569
    if (!m_table) {
3,342✔
570
        return false;
6✔
571
    }
6✔
572
    else if (m_collection_source) {
3,336✔
573
        return false;
6✔
574
    }
6✔
575
    else if (m_source_column_key) {
3,330✔
576
        return false;
6✔
577
    }
6✔
578
    else if (!m_query) {
3,324✔
579
        return false;
66✔
580
    }
66✔
581
    else {
3,258✔
582
        m_query->m_table.check();
3,258✔
583
        return m_query->produces_results_in_table_order() && !m_descriptor_ordering.will_apply_sort();
3,258✔
584
    }
3,258✔
585
}
3,342✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc