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

realm / realm-core / github_pull_request_278228

04 Oct 2023 10:15PM UTC coverage: 91.582% (+0.007%) from 91.575%
github_pull_request_278228

Pull #7029

Evergreen

tgoyne
Use UNITTEST_LOG_LEVEL in objectstore tests

For historical reasons core and sync tests use the UNITTEST_LOG_LEVEL
environment variable to determine the test log level, while object store tests
used a build time setting. This brings them into alignment on using the env
variable, and applies it via setting the default log level on startup in a
single place.
Pull Request #7029: Use UNITTEST_LOG_LEVEL in objectstore tests

94218 of 173442 branches covered (0.0%)

46 of 54 new or added lines in 5 files covered. (85.19%)

51 existing lines in 12 files now uncovered.

230351 of 251523 relevant lines covered (91.58%)

6704577.96 hits per line

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

93.91
/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
void TableView::KeyValues::copy_from(const KeyValues& rhs)
29
{
9,555✔
30
    Allocator& rhs_alloc = rhs.get_alloc();
9,555✔
31

4,782✔
32
    // Destroy current tree
4,782✔
33
    destroy();
9,555✔
34

4,782✔
35
    if (rhs.is_attached()) {
9,555✔
36
        // Take copy of other tree
687✔
37
        MemRef mem(rhs.get_ref(), rhs_alloc);
1,365✔
38
        MemRef copy_mem = Array::clone(mem, rhs_alloc, m_alloc); // Throws
1,365✔
39

687✔
40
        init_from_ref(copy_mem.get_ref());
1,365✔
41
    }
1,365✔
42
}
9,555✔
43

44
void TableView::KeyValues::move_from(KeyValues& rhs)
45
{
228,294✔
46
    // Destroy current tree
113,760✔
47
    destroy();
228,294✔
48

113,760✔
49
    m_root = std::move(rhs.m_root);
228,294✔
50
    if (m_root)
228,294✔
51
        m_root->change_owner(this);
197,364✔
52
    m_size = rhs.m_size;
228,294✔
53
    rhs.m_size = 0;
228,294✔
54
}
228,294✔
55

56
TableView::TableView(TableView& src, Transaction* tr, PayloadPolicy policy_mode)
57
    : m_source_column_key(src.m_source_column_key)
58
{
55,887✔
59
    bool was_in_sync = src.is_in_sync();
55,887✔
60
    if (src.m_query)
55,887✔
61
        m_query = Query(*src.m_query, tr, policy_mode);
55,281✔
62
    m_table = tr->import_copy_of(src.m_table);
55,887✔
63

28,176✔
64
    if (policy_mode == PayloadPolicy::Stay)
55,887✔
65
        was_in_sync = false;
96✔
66

28,176✔
67
    VersionID src_version =
55,887✔
68
        dynamic_cast<Transaction*>(src.m_table->get_parent_group())->get_version_of_current_transaction();
55,887✔
69
    if (src_version != tr->get_version_of_current_transaction())
55,887✔
70
        was_in_sync = false;
18✔
71

28,176✔
72
    m_table = tr->import_copy_of(src.m_table);
55,887✔
73
    m_collection_source = tr->import_copy_of(src.m_collection_source);
55,887✔
74
    if (src.m_source_column_key) {
55,887✔
75
        m_linked_obj = tr->import_copy_of(src.m_linked_obj);
606✔
76
    }
606✔
77

28,176✔
78
    if (was_in_sync)
55,887✔
79
        get_dependencies(m_last_seen_versions);
55,767✔
80

28,176✔
81
    // don't use methods which throw after this point...or m_table_view_key_values will leak
28,176✔
82
    if (policy_mode == PayloadPolicy::Copy && src.m_key_values.is_attached()) {
55,887✔
83
        m_key_values.copy_from(src.m_key_values);
696✔
84
    }
696✔
85
    else if (policy_mode == PayloadPolicy::Move && src.m_key_values.is_attached())
55,191✔
86
        // Requires that 'src' is a writable object
27,774✔
87
        m_key_values.move_from(src.m_key_values);
55,083✔
88
    else {
108✔
89
        m_key_values.create();
108✔
90
    }
108✔
91
    if (policy_mode == PayloadPolicy::Move) {
55,887✔
92
        src.m_last_seen_versions.clear();
55,089✔
93
    }
55,089✔
94
    m_descriptor_ordering = src.m_descriptor_ordering;
55,887✔
95
    m_limit = src.m_limit;
55,887✔
96
}
55,887✔
97

98
// Aggregates ----------------------------------------------------
99

100
template <typename T, Action AggregateOpType>
101
struct Aggregator {
102
};
103

104
template <typename T>
105
struct Aggregator<T, act_Sum> {
106
    using AggType = typename aggregate_operations::Sum<typename util::RemoveOptional<T>::type>;
107
};
108

109
template <typename T>
110
struct Aggregator<T, act_Average> {
111
    using AggType = typename aggregate_operations::Average<typename util::RemoveOptional<T>::type>;
112
};
113

114
template <typename T>
115
struct Aggregator<T, act_Min> {
116
    using AggType = typename aggregate_operations::Minimum<typename util::RemoveOptional<T>::type>;
117
};
118

119
template <typename T>
120
struct Aggregator<T, act_Max> {
121
    using AggType = typename aggregate_operations::Maximum<typename util::RemoveOptional<T>::type>;
122
};
123

124
template <Action action, typename T>
125
Mixed TableView::aggregate(ColKey column_key, size_t* result_count, ObjKey* return_key) const
126
{
4,230✔
127
    static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Average);
4,230✔
128
    REALM_ASSERT(m_table->valid_column(column_key));
4,230!
129

2,115✔
130
    size_t non_nulls = 0;
4,230✔
131
    typename Aggregator<T, action>::AggType agg;
4,230✔
132
    ObjKey last_accumulated_key = null_key;
4,230✔
133
    for (size_t tv_index = 0; tv_index < m_key_values.size(); ++tv_index) {
57,798!
134
        ObjKey key(get_key(tv_index));
53,568✔
135

26,394✔
136
        // skip detached references:
26,394✔
137
        if (key == realm::null_key)
53,568!
138
            continue;
×
139

26,394✔
140
        const Obj obj = m_table->try_get_object(key);
53,568✔
141
        // aggregation must be robust in the face of stale keys:
26,394✔
142
        if (!obj.is_valid())
53,568!
143
            continue;
24✔
144

26,382✔
145
        if (obj.is_null(column_key))
53,544!
146
            continue;
8,148✔
147

22,458✔
148
        auto v = obj.get<T>(column_key);
45,396✔
149
        if (agg.accumulate(v)) {
45,396!
150
            ++non_nulls;
30,900✔
151
            if constexpr (action == act_Min || action == act_Max) {
30,900✔
152
                last_accumulated_key = key;
15,132✔
153
            }
15,132✔
154
        }
30,900✔
155
    }
45,396✔
156

2,115✔
157
    if (result_count)
4,230!
158
        *result_count = non_nulls;
696✔
159

2,115✔
160
    if constexpr (action == act_Max || action == act_Min) {
4,230✔
161
        if (return_key) {
2,532!
162
            *return_key = last_accumulated_key;
2,040✔
163
        }
2,040✔
164
    }
2,532✔
165
    else {
1,698✔
166
        static_cast<void>(last_accumulated_key);
1,698✔
167
        static_cast<void>(return_key);
1,698✔
168
    }
1,698✔
169

2,115✔
170
    if (!agg.is_null()) {
4,230!
171
        return agg.result();
3,258✔
172
    }
3,258✔
173
    if (action == act_Sum) {
972✔
174
        if (std::is_same_v<T, Mixed>) {
×
175
            return Decimal128{0};
×
176
        }
×
177
        return T{};
×
178
    }
×
179
    return Mixed();
972✔
180
}
972✔
181

182
template <typename T>
183
size_t TableView::aggregate_count(ColKey column_key, T count_target) const
184
{
48✔
185
    REALM_ASSERT(m_table->valid_column(column_key));
48!
186

24✔
187
    if ((m_key_values.size()) == 0) {
48!
188
        return {};
×
189
    }
×
190

24✔
191
    size_t cnt = 0;
48✔
192
    for (size_t tv_index = 0; tv_index < m_key_values.size(); ++tv_index) {
240!
193
        ObjKey key(get_key(tv_index));
192✔
194

96✔
195
        // skip detached references:
96✔
196
        if (key == realm::null_key)
192!
197
            continue;
×
198

96✔
199
        const Obj obj = m_table->try_get_object(key);
192✔
200
        if (!obj.is_valid())
192!
201
            continue;
×
202

96✔
203
        auto v = obj.get<T>(column_key);
192✔
204
        if (v == count_target) {
192!
205
            cnt++;
102✔
206
        }
102✔
207
    }
192✔
208

24✔
209
    return cnt;
48✔
210
}
48✔
211

212
// Count
213
size_t TableView::count_int(ColKey column_key, int64_t target) const
214
{
12✔
215
    if (m_table->is_nullable(column_key))
12✔
216
        return aggregate_count<util::Optional<int64_t>>(column_key, target);
×
217
    else
12✔
218
        return aggregate_count<int64_t>(column_key, target);
12✔
219
}
12✔
220
size_t TableView::count_float(ColKey column_key, float target) const
221
{
12✔
222
    return aggregate_count<float>(column_key, target);
12✔
223
}
12✔
224
size_t TableView::count_double(ColKey column_key, double target) const
225
{
12✔
226
    return aggregate_count<double>(column_key, target);
12✔
227
}
12✔
228
size_t TableView::count_timestamp(ColKey column_key, Timestamp target) const
229
{
12✔
230
    return aggregate_count<Timestamp>(column_key, target);
12✔
231
}
12✔
232
size_t TableView::count_decimal(ColKey column_key, Decimal128 target) const
233
{
×
234
    return aggregate_count<Decimal128>(column_key, target);
×
235
}
×
236
size_t TableView::count_mixed(ColKey column_key, Mixed target) const
237
{
×
238
    return aggregate_count<Mixed>(column_key, target);
×
239
}
×
240

241
template <Action action>
242
std::optional<Mixed> TableView::aggregate(ColKey column_key, size_t* count, ObjKey* return_key) const
243
{
4,422✔
244
    static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Average);
4,422✔
245
    m_table->check_column(column_key);
4,422✔
246
    if (column_key.is_collection()) {
4,422✔
247
        return std::nullopt;
48✔
248
    }
48✔
249

2,187✔
250
    switch (column_key.get_type()) {
4,374✔
251
        case col_type_Int:
1,596✔
252
            if (m_table->is_nullable(column_key))
1,596✔
253
                return aggregate<action, util::Optional<int64_t>>(column_key, count, return_key);
1,470✔
254
            return aggregate<action, int64_t>(column_key, count, return_key);
126✔
255
        case col_type_Float:
1,506✔
256
            return aggregate<action, float>(column_key, count, return_key);
1,506✔
257
        case col_type_Double:
342✔
258
            return aggregate<action, double>(column_key, count, return_key);
342✔
259
        case col_type_Timestamp:
99✔
260
            if constexpr (action == act_Min || action == act_Max) {
858✔
261
                return aggregate<action, Timestamp>(column_key, count, return_key);
786✔
262
            }
786✔
263
            break;
×
264
        case col_type_Decimal:
✔
265
            return aggregate<action, Decimal128>(column_key, count, return_key);
×
266
        case col_type_Mixed:
✔
267
            return aggregate<action, Mixed>(column_key, count, return_key);
×
268
        default:
✔
269
            break;
×
270
    }
72✔
271
    return util::none;
72✔
272
}
72✔
273

274
util::Optional<Mixed> TableView::min(ColKey column_key, ObjKey* return_key) const
275
{
1,290✔
276
    return aggregate<act_Min>(column_key, nullptr, return_key);
1,290✔
277
}
1,290✔
278

279
util::Optional<Mixed> TableView::max(ColKey column_key, ObjKey* return_key) const
280
{
1,302✔
281
    return aggregate<act_Max>(column_key, nullptr, return_key);
1,302✔
282
}
1,302✔
283

284
util::Optional<Mixed> TableView::sum(ColKey column_key) const
285
{
900✔
286
    return aggregate<act_Sum>(column_key, nullptr, nullptr);
900✔
287
}
900✔
288

289
util::Optional<Mixed> TableView::avg(ColKey column_key, size_t* value_count) const
290
{
930✔
291
    return aggregate<act_Average>(column_key, value_count, nullptr);
930✔
292
}
930✔
293

294
void TableView::to_json(std::ostream& out, size_t link_depth, const std::map<std::string, std::string>& renames,
295
                        JSONOutputMode mode) const
296
{
60✔
297
    // Represent table as list of objects
30✔
298
    out << "[";
60✔
299

30✔
300
    const size_t row_count = size();
60✔
301
    bool first = true;
60✔
302
    for (size_t r = 0; r < row_count; ++r) {
540✔
303
        if (ObjKey key = get_key(r)) {
480✔
304
            if (first) {
480✔
305
                first = false;
60✔
306
            }
60✔
307
            else {
420✔
308
                out << ",";
420✔
309
            }
420✔
310
            m_table->get_object(key).to_json(out, link_depth, renames, mode);
480✔
311
        }
480✔
312
    }
480✔
313

30✔
314
    out << "]";
60✔
315
}
60✔
316

317
bool TableView::depends_on_deleted_object() const
318
{
42✔
319
    if (m_collection_source) {
42✔
320
        return !m_collection_source->get_owning_obj().is_valid();
12✔
321
    }
12✔
322

15✔
323
    if (m_source_column_key && !m_linked_obj.is_valid()) {
30✔
324
        return true;
12✔
325
    }
12✔
326
    else if (m_query && m_query->m_source_table_view) {
18✔
327
        return m_query->m_source_table_view->depends_on_deleted_object();
6✔
328
    }
6✔
329
    return false;
12✔
330
}
12✔
331

332
void TableView::get_dependencies(TableVersions& ret) const
333
{
1,904,001✔
334
    auto table = m_table ? m_table.unchecked_ptr() : nullptr;
2,148,485,848✔
335
    if (m_source_column_key && m_linked_obj) {
1,904,001✔
336
        // m_source_column_key is set when this TableView was created by Table::get_backlink_view().
1,056✔
337
        if (auto linked_table = m_linked_obj.get_table()) {
2,112✔
338
            ret.emplace_back(linked_table->get_key(), linked_table->get_content_version());
2,112✔
339
        }
2,112✔
340
    }
2,112✔
341
    else if (m_query) {
1,954,491✔
342
        m_query->get_outside_versions(ret);
1,952,889✔
343
    }
1,952,889✔
344
    else {
2,147,485,249✔
345
        // This TableView was created by Table::get_distinct_view() or get_sorted_view() on collections
2,147,483,647✔
346
        ret.emplace_back(table->get_key(), table->get_content_version());
2,147,485,249✔
347
    }
2,147,485,249✔
348

899,232✔
349
    // Finally add dependencies from sort/distinct
899,232✔
350
    if (table) {
1,922,181✔
351
        m_descriptor_ordering.get_versions(table->get_parent_group(), ret);
1,922,181✔
352
    }
1,922,181✔
353
}
1,904,001✔
354

355
bool TableView::is_in_sync() const
356
{
274,491✔
357
    return m_table && !has_changed();
274,491✔
358
}
274,491✔
359

360
void TableView::sync_if_needed() const
361
{
176,400✔
362
    if (!is_in_sync()) {
176,400✔
363
        // FIXME: Is this a reasonable handling of constness?
27,738✔
364
        const_cast<TableView*>(this)->do_sync();
55,062✔
365
    }
55,062✔
366
}
176,400✔
367

368
void TableView::update_query(const Query& q)
369
{
6✔
370
    REALM_ASSERT(m_query);
6✔
371
    REALM_ASSERT(m_query->m_table);
6✔
372
    REALM_ASSERT(m_query->m_table == q.m_table);
6✔
373

3✔
374
    m_query = q;
6✔
375
    do_sync();
6✔
376
}
6✔
377

378
void TableView::clear()
379
{
4,767✔
380
    m_table.check();
4,767✔
381

2,385✔
382
    // If distinct is applied then removing an object may leave us out of sync
2,385✔
383
    // if there's another object with the same value in the distinct column
2,385✔
384
    // as the removed object
2,385✔
385
    bool sync_to_keep =
4,767✔
386
        m_last_seen_versions == get_dependency_versions() && !m_descriptor_ordering.will_apply_distinct();
4,767✔
387

2,385✔
388
    _impl::TableFriend::batch_erase_rows(*get_parent(), m_key_values); // Throws
4,767✔
389

2,385✔
390
    m_key_values.clear();
4,767✔
391

2,385✔
392
    // It is important to not accidentally bring us in sync, if we were
2,385✔
393
    // not in sync to start with:
2,385✔
394
    if (sync_to_keep)
4,767✔
395
        m_last_seen_versions = get_dependency_versions();
4,749✔
396
}
4,767✔
397

398
void TableView::distinct(ColKey column)
399
{
144✔
400
    distinct(DistinctDescriptor({{column}}));
144✔
401
}
144✔
402

403
/// Remove rows that are duplicated with respect to the column set passed as argument.
404
/// Will keep original sorting order so that you can both have a distinct and sorted view.
405
void TableView::distinct(DistinctDescriptor columns)
406
{
432✔
407
    m_descriptor_ordering.append_distinct(std::move(columns));
432✔
408
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
432✔
409

216✔
410
    do_sync();
432✔
411
}
432✔
412

413
void TableView::limit(LimitDescriptor lim)
414
{
12✔
415
    m_descriptor_ordering.append_limit(std::move(lim));
12✔
416
    do_sync();
12✔
417
}
12✔
418

419
void TableView::apply_descriptor_ordering(const DescriptorOrdering& new_ordering)
420
{
41,610✔
421
    m_descriptor_ordering = new_ordering;
41,610✔
422
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
41,610✔
423

21,132✔
424
    do_sync();
41,610✔
425
}
41,610✔
426

427
std::string TableView::get_descriptor_ordering_description() const
428
{
18✔
429
    return m_descriptor_ordering.get_description(m_table);
18✔
430
}
18✔
431

432
// Sort according to one column
433
void TableView::sort(ColKey column, bool ascending)
434
{
444✔
435
    sort(SortDescriptor({{column}}, {ascending}));
444✔
436
}
444✔
437

438
// Sort according to multiple columns, user specified order on each column
439
void TableView::sort(SortDescriptor order)
440
{
1,014✔
441
    m_descriptor_ordering.append_sort(std::move(order), SortDescriptor::MergeMode::prepend);
1,014✔
442
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
1,014✔
443

507✔
444
    do_sort(m_descriptor_ordering);
1,014✔
445
}
1,014✔
446

447

448
void TableView::do_sync()
449
{
1,577,499✔
450
    util::CriticalSection cs(m_race_detector);
1,577,499✔
451
    // This TableView can be "born" from 4 different sources:
759,816✔
452
    // - LinkView
759,816✔
453
    // - Query::find_all()
759,816✔
454
    // - Table::get_distinct_view()
759,816✔
455
    // - Table::get_backlink_view()
759,816✔
456
    // Here we sync with the respective source.
759,816✔
457
    m_last_seen_versions.clear();
1,577,499✔
458

759,816✔
459
    if (m_collection_source) {
1,577,499✔
460
        m_key_values.clear();
102✔
461
        auto sz = m_collection_source->size();
102✔
462
        for (size_t i = 0; i < sz; i++) {
330✔
463
            m_key_values.add(m_collection_source->get_key(i));
228✔
464
        }
228✔
465
    }
102✔
466
    else if (m_source_column_key) {
1,577,397✔
467
        m_key_values.clear();
756✔
468
        if (m_table && m_linked_obj.is_valid()) {
756✔
469
            if (m_table->valid_column(m_source_column_key)) { // return empty result, if column has been removed
744✔
470
                ColKey backlink_col = m_table->get_opposite_column(m_source_column_key);
738✔
471
                REALM_ASSERT(backlink_col);
738✔
472
                auto backlinks = m_linked_obj.get_all_backlinks(backlink_col);
738✔
473
                for (auto k : backlinks) {
723✔
474
                    m_key_values.add(k);
708✔
475
                }
708✔
476
            }
738✔
477
        }
744✔
478
    }
756✔
479
    // FIXME: Unimplemented for link to a column
759,387✔
480
    else {
1,576,641✔
481
        REALM_ASSERT(m_query);
1,576,641✔
482
        m_query->m_table.check();
1,576,641✔
483

759,387✔
484
        // valid query, so clear earlier results and reexecute it.
759,387✔
485
        if (m_key_values.is_attached())
1,576,641✔
486
            m_key_values.clear();
1,502,283✔
487
        else
74,358✔
488
            m_key_values.create();
74,358✔
489

759,387✔
490
        if (m_query->m_view)
1,576,641✔
491
            m_query->m_view->sync_if_needed();
1,101✔
492
        QueryStateFindAll<KeyColumn> st(m_key_values, m_limit);
1,576,641✔
493
        m_query->do_find_all(st);
1,576,641✔
494
    }
1,576,641✔
495

759,816✔
496
    do_sort(m_descriptor_ordering);
1,577,499✔
497

759,816✔
498
    get_dependencies(m_last_seen_versions);
1,577,499✔
499
}
1,577,499✔
500

501
void TableView::do_sort(const DescriptorOrdering& ordering)
502
{
1,551,039✔
503
    if (ordering.is_empty())
1,551,039✔
504
        return;
1,618,149✔
505
    size_t sz = size();
2,147,502,223✔
506
    if (sz == 0)
2,147,502,223✔
507
        return;
18,015✔
508

2,147,483,647✔
509
    // Gather the current rows into a container we can use std algorithms on
2,147,483,647✔
510
    size_t detached_ref_count = 0;
2,147,493,532✔
511
    BaseDescriptor::IndexPairs index_pairs;
2,147,493,532✔
512
    index_pairs.reserve(sz);
2,147,493,532✔
513
    // always put any detached refs at the end of the sort
2,147,483,647✔
514
    // FIXME: reconsider if this is the right thing to do
2,147,483,647✔
515
    // FIXME: consider specialized implementations in derived classes
2,147,483,647✔
516
    // (handling detached refs is not required in linkviews)
2,147,483,647✔
517
    for (size_t t = 0; t < sz; t++) {
2,147,618,068✔
518
        ObjKey key = get_key(t);
249,081✔
519
        if (m_table->is_valid(key)) {
249,081✔
520
            index_pairs.emplace_back(key, t);
249,081✔
521
        }
249,081✔
UNCOV
522
        else
×
UNCOV
523
            ++detached_ref_count;
×
524
    }
249,081✔
525

2,147,483,647✔
526
    const int num_descriptors = int(ordering.size());
2,147,493,532✔
527
    for (int desc_ndx = 0; desc_ndx < num_descriptors; ++desc_ndx) {
2,147,504,038✔
528
        const BaseDescriptor* base_descr = ordering[desc_ndx];
21,057✔
529
        const BaseDescriptor* next = ((desc_ndx + 1) < num_descriptors) ? ordering[desc_ndx + 1] : nullptr;
19,776✔
530
        BaseDescriptor::Sorter predicate = base_descr->sorter(*m_table, index_pairs);
21,057✔
531

10,551✔
532
        // Sorting can be specified by multiple columns, so that if two entries in the first column are
10,551✔
533
        // identical, then the rows are ordered according to the second column, and so forth. For the
10,551✔
534
        // first column, we cache all the payload of fields of the view in a std::vector<Mixed>
10,551✔
535
        predicate.cache_first_column(index_pairs);
21,057✔
536

10,551✔
537
        base_descr->execute(index_pairs, predicate, next);
21,057✔
538
    }
21,057✔
539
    // Apply the results
2,147,483,647✔
540
    m_limit_count = index_pairs.m_removed_by_limit;
2,147,493,532✔
541
    m_key_values.clear();
2,147,493,532✔
542
    for (auto& pair : index_pairs) {
2,147,576,530✔
543
        m_key_values.add(pair.key_for_object);
185,775✔
544
    }
185,775✔
545
    for (size_t t = 0; t < detached_ref_count; ++t)
2,147,493,532✔
546
        m_key_values.add(null_key);
×
547
}
2,147,493,532✔
548

549
bool TableView::is_in_table_order() const
550
{
2,598✔
551
    if (!m_table) {
2,598✔
552
        return false;
6✔
553
    }
6✔
554
    else if (m_collection_source) {
2,592✔
555
        return false;
6✔
556
    }
6✔
557
    else if (m_source_column_key) {
2,586✔
558
        return false;
6✔
559
    }
6✔
560
    else if (!m_query) {
2,580✔
561
        return false;
66✔
562
    }
66✔
563
    else {
2,514✔
564
        m_query->m_table.check();
2,514✔
565
        return m_query->produces_results_in_table_order() && !m_descriptor_ordering.will_apply_sort();
2,514✔
566
    }
2,514✔
567
}
2,598✔
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

© 2025 Coveralls, Inc