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

realm / realm-core / thomas.goyne_112

27 Oct 2023 10:49AM UTC coverage: 91.586% (+0.02%) from 91.571%
thomas.goyne_112

push

Evergreen

web-flow
Merge pull request #7085 from realm/release/13.23.2

Release/13.23.2

91754 of 168238 branches covered (0.0%)

230143 of 251285 relevant lines covered (91.59%)

7082763.83 hits per line

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

96.15
/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
{
57,330✔
31
    bool was_in_sync = src.is_in_sync();
57,330✔
32
    if (src.m_query)
57,330✔
33
        m_query = Query(*src.m_query, tr, policy_mode);
56,724✔
34
    m_table = tr->import_copy_of(src.m_table);
57,330✔
35

28,059✔
36
    if (policy_mode == PayloadPolicy::Stay)
57,330✔
37
        was_in_sync = false;
96✔
38

28,059✔
39
    VersionID src_version =
57,330✔
40
        dynamic_cast<Transaction*>(src.m_table->get_parent_group())->get_version_of_current_transaction();
57,330✔
41
    if (src_version != tr->get_version_of_current_transaction())
57,330✔
42
        was_in_sync = false;
18✔
43

28,059✔
44
    m_table = tr->import_copy_of(src.m_table);
57,330✔
45
    m_collection_source = tr->import_copy_of(src.m_collection_source);
57,330✔
46
    if (src.m_source_column_key) {
57,330✔
47
        m_linked_obj = tr->import_copy_of(src.m_linked_obj);
606✔
48
    }
606✔
49

28,059✔
50
    if (was_in_sync)
57,330✔
51
        get_dependencies(m_last_seen_versions);
57,210✔
52

28,059✔
53
    // don't use methods which throw after this point...or m_table_view_key_values will leak
28,059✔
54
    if (policy_mode == PayloadPolicy::Copy && src.m_key_values.is_attached()) {
57,330✔
55
        m_key_values = src.m_key_values;
702✔
56
    }
702✔
57
    else if (policy_mode == PayloadPolicy::Move && src.m_key_values.is_attached())
56,628✔
58
        // Requires that 'src' is a writable object
27,660✔
59
        m_key_values = std::move(src.m_key_values);
56,532✔
60
    else {
96✔
61
        m_key_values.create();
96✔
62
    }
96✔
63
    if (policy_mode == PayloadPolicy::Move) {
57,330✔
64
        src.m_last_seen_versions.clear();
56,532✔
65
    }
56,532✔
66
    m_descriptor_ordering = src.m_descriptor_ordering;
57,330✔
67
    m_limit = src.m_limit;
57,330✔
68
}
57,330✔
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,498!
106
        ObjKey key(get_key(tv_index));
53,268✔
107

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

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

26,442✔
117
        if (obj.is_null(column_key))
53,244!
118
            continue;
8,268✔
119

22,218✔
120
        auto v = obj.get<T>(column_key);
44,976✔
121
        if (agg.accumulate(v)) {
44,976!
122
            ++non_nulls;
30,570✔
123
            if constexpr (action == act_Min || action == act_Max) {
30,570✔
124
                last_accumulated_key = key;
14,970✔
125
            }
14,970✔
126
        }
30,570✔
127
    }
44,976✔
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,186✔
144
    }
3,186✔
145
    if (action == act_Sum) {
1,044✔
146
        if (std::is_same_v<T, Mixed>) {
×
147
            return Decimal128{0};
×
148
        }
×
149
        return T{};
×
150
    }
×
151
    return Mixed();
1,044✔
152
}
1,044✔
153

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

4,422✔
159
    if ((m_key_values.size()) == 0) {
4,422✔
160
        return {};
48✔
161
    }
48✔
162

2,187✔
163
    size_t cnt = 0;
4,374✔
164
    for (size_t tv_index = 0; tv_index < m_key_values.size(); ++tv_index) {
1,596✔
165
        ObjKey key(get_key(tv_index));
1,596✔
166

1,470✔
167
        // skip detached references:
126✔
168
        if (key == realm::null_key)
1,506✔
169
            continue;
1,506✔
170

342✔
171
        const Obj obj = m_table->try_get_object(key);
342✔
172
        if (!obj.is_valid())
99✔
173
            continue;
858✔
174

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

×
181
    return cnt;
✔
182
}
×
183

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

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

420✔
222
    switch (column_key.get_type()) {
420✔
223
        case col_type_Int:
480✔
224
            if (m_table->is_nullable(column_key))
480✔
225
                return aggregate<action, util::Optional<int64_t>>(column_key, count, return_key);
480✔
226
            return aggregate<action, int64_t>(column_key, count, return_key);
30✔
227
        case col_type_Float:
60✔
228
            return aggregate<action, float>(column_key, count, return_key);
60✔
229
        case col_type_Double:
230
            return aggregate<action, double>(column_key, count, return_key);
231
        case col_type_Timestamp:
42✔
232
            if constexpr (action == act_Min || action == act_Max) {
42✔
233
                return aggregate<action, Timestamp>(column_key, count, return_key);
12✔
234
            }
12✔
235
            break;
15✔
236
        case col_type_Decimal:
30✔
237
            return aggregate<action, Decimal128>(column_key, count, return_key);
12✔
238
        case col_type_Mixed:
12✔
239
            return aggregate<action, Mixed>(column_key, count, return_key);
18✔
240
        default:
6✔
241
            break;
6✔
242
    }
12✔
243
    return util::none;
12✔
244
}
245

246
util::Optional<Mixed> TableView::min(ColKey column_key, ObjKey* return_key) const
1,848,558✔
247
{
2,148,459,301✔
248
    return aggregate<act_Min>(column_key, nullptr, return_key);
1,848,558✔
249
}
1,056✔
250

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

1,893,966✔
256
util::Optional<Mixed> TableView::sum(ColKey column_key) const
1,893,966✔
257
{
2,147,495,797✔
258
    return aggregate<act_Sum>(column_key, nullptr, nullptr);
2,147,483,647✔
259
}
2,147,495,797✔
260

2,147,495,797✔
261
util::Optional<Mixed> TableView::avg(ColKey column_key, size_t* value_count) const
863,811✔
262
{
863,811✔
263
    return aggregate<act_Average>(column_key, value_count, nullptr);
1,848,558✔
264
}
1,826,475✔
265

1,826,475✔
266
void TableView::to_json(std::ostream& out, size_t link_depth, const std::map<std::string, std::string>& renames,
1,848,558✔
267
                        JSONOutputMode mode) const
268
{
269
    // Represent table as list of objects
266,418✔
270
    out << "[";
266,445✔
271

266,418✔
272
    const size_t row_count = size();
273
    bool first = true;
274
    for (size_t r = 0; r < row_count; ++r) {
159,876✔
275
        if (ObjKey key = get_key(r)) {
159,876✔
276
            if (first) {
27,609✔
277
                first = false;
56,496✔
278
            }
56,496✔
279
            else {
159,876✔
280
                out << ",";
281
            }
282
            m_table->get_object(key).to_json(out, link_depth, renames, mode);
12✔
283
        }
12✔
284
    }
12✔
285

12✔
286
    out << "]";
6✔
287
}
12✔
288

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

2,385✔
295
    if (m_source_column_key && !m_linked_obj.is_valid()) {
2,385✔
296
        return true;
2,385✔
297
    }
2,385✔
298
    else if (m_query && m_query->m_source_table_view) {
4,767✔
299
        return m_query->m_source_table_view->depends_on_deleted_object();
4,767✔
300
    }
2,385✔
301
    return false;
2,385✔
302
}
2,511,732✔
303

2,511,732✔
304
void TableView::get_dependencies(TableVersions& ret) const
2,511,732✔
305
{
4,767✔
306
    auto table = m_table ? m_table.unchecked_ptr() : nullptr;
2,385✔
307
    if (m_source_column_key && m_linked_obj) {
4,767✔
308
        // m_source_column_key is set when this TableView was created by Table::get_backlink_view().
2,385✔
309
        if (auto linked_table = m_linked_obj.get_table()) {
2,385✔
310
            ret.emplace_back(linked_table->get_key(), linked_table->get_content_version());
2,385✔
311
        }
4,767✔
312
    }
4,749✔
313
    else if (m_query) {
4,767✔
314
        m_query->get_outside_versions(ret);
315
    }
316
    else {
144✔
317
        // This TableView was created by Table::get_distinct_view() or get_sorted_view() on collections
144✔
318
        ret.emplace_back(table->get_key(), table->get_content_version());
144✔
319
    }
320

321
    // Finally add dependencies from sort/distinct
322
    if (table) {
323
        m_descriptor_ordering.get_versions(table->get_parent_group(), ret);
432✔
324
    }
432✔
325
}
432✔
326

216✔
327
bool TableView::is_in_sync() const
432✔
328
{
432✔
329
    return m_table && !has_changed();
330
}
331

12✔
332
void TableView::sync_if_needed() const
12✔
333
{
12✔
334
    if (!is_in_sync()) {
12✔
335
        // FIXME: Is this a reasonable handling of constness?
336
        const_cast<TableView*>(this)->do_sync();
337
    }
12✔
338
}
12✔
339

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

38,403✔
346
    m_query = q;
19,494✔
347
    do_sync();
38,403✔
348
}
38,403✔
349

350
void TableView::clear()
351
{
18✔
352
    m_table.check();
18✔
353

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

450✔
360
    // Remove all invalid keys
361
    auto it = std::remove_if(m_key_values.begin(), m_key_values.end(), [this](const ObjKey& key) {
362
        return !m_table->is_valid(key);
363
    });
1,020✔
364
    m_key_values.erase(it, m_key_values.end());
1,020✔
365

1,020✔
366
    _impl::TableFriend::batch_erase_objects(*get_parent(), m_key_values); // Throws
510✔
367

1,020✔
368
    // It is important to not accidentally bring us in sync, if we were
1,020✔
369
    // not in sync to start with:
370
    if (sync_to_keep)
371
        m_last_seen_versions = get_dependency_versions();
372
}
1,560,051✔
373

1,560,051✔
374
void TableView::distinct(ColKey column)
771,123✔
375
{
771,123✔
376
    distinct(DistinctDescriptor({{column}}));
771,123✔
377
}
771,123✔
378

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

330✔
386
    do_sync();
228✔
387
}
228✔
388

102✔
389
void TableView::limit(LimitDescriptor lim)
1,559,949✔
390
{
756✔
391
    m_descriptor_ordering.append_limit(std::move(lim));
756✔
392
    do_sync();
744✔
393
}
738✔
394

738✔
395
void TableView::filter(FilterDescriptor filter)
738✔
396
{
723✔
397
    m_descriptor_ordering.append_filter(std::move(filter));
708✔
398
    do_sync();
708✔
399
}
738✔
400

744✔
401
void TableView::apply_descriptor_ordering(const DescriptorOrdering& new_ordering)
756✔
402
{
770,694✔
403
    m_descriptor_ordering = new_ordering;
1,559,193✔
404
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
1,559,193✔
405

1,559,193✔
406
    do_sync();
770,694✔
407
}
770,694✔
408

1,559,193✔
409
std::string TableView::get_descriptor_ordering_description() const
1,534,521✔
410
{
24,672✔
411
    return m_descriptor_ordering.get_description(m_table);
24,672✔
412
}
770,694✔
413

1,559,193✔
414
// Sort according to one column
1,101✔
415
void TableView::sort(ColKey column, bool ascending)
1,559,193✔
416
{
1,559,193✔
417
    sort(SortDescriptor({{column}}, {ascending}));
32,307✔
418
}
32,307✔
419

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

1,559,193✔
426
    apply_descriptors(m_descriptor_ordering);
1,559,193✔
427
}
771,123✔
428

1,560,051✔
429

771,123✔
430
void TableView::do_sync()
1,560,051✔
431
{
1,560,051✔
432
    util::CriticalSection cs(m_race_detector);
433
    // This TableView can be "born" from 4 different sources:
434
    // - LinkView
1,588,710✔
435
    // - Query::find_all()
1,588,710✔
436
    // - Table::get_distinct_view()
1,620,456✔
437
    // - Table::get_backlink_view()
2,147,504,080✔
438
    // Here we sync with the respective source.
2,147,504,080✔
439
    m_last_seen_versions.clear();
14,922✔
440

2,147,483,647✔
441
    if (m_collection_source) {
2,147,483,647✔
442
        m_key_values.clear();
2,147,496,901✔
443
        auto sz = m_collection_source->size();
2,147,496,901✔
444
        for (size_t i = 0; i < sz; i++) {
2,147,496,901✔
445
            m_key_values.add(m_collection_source->get_key(i));
2,147,483,647✔
446
        }
2,147,492,767✔
447
    }
18,261✔
448
    else if (m_source_column_key) {
186,444✔
449
        m_key_values.clear();
186,444✔
450
        if (m_table && m_linked_obj.is_valid()) {
186,444✔
451
            if (m_table->valid_column(m_source_column_key)) { // return empty result, if column has been removed
18,261✔
452
                ColKey backlink_col = m_table->get_opposite_column(m_source_column_key);
×
453
                REALM_ASSERT(backlink_col);
18,261✔
454
                auto backlinks = m_linked_obj.get_all_backlinks(backlink_col);
18,261✔
455
                for (auto k : backlinks) {
2,147,483,647✔
456
                    m_key_values.add(k);
2,147,492,779✔
457
                }
18,285✔
458
            }
18,285✔
459
        }
9,153✔
460
    }
9,153✔
461
    // FIXME: Unimplemented for link to a column
9,153✔
462
    else {
9,153✔
463
        REALM_ASSERT(m_query);
267,042✔
464
        m_query->m_table.check();
248,757✔
465

248,757✔
466
        // valid query, so clear earlier results and reexecute it.
248,757✔
467
        if (m_key_values.is_attached())
248,757✔
468
            m_key_values.clear();
×
469
        else
×
470
            m_key_values.create();
248,757✔
471

18,285✔
472
        if (m_query->m_view)
18,285✔
473
            m_query->m_view->sync_if_needed();
2,147,483,647✔
474
        size_t limit = m_limit;
2,147,496,901✔
475
        if (!m_descriptor_ordering.is_empty()) {
2,147,507,383✔
476
            auto type = m_descriptor_ordering[0]->get_type();
21,003✔
477
            if (type == DescriptorType::Limit) {
19,701✔
478
                size_t l = static_cast<const LimitDescriptor*>(m_descriptor_ordering[0])->get_limit();
10,521✔
479
                if (l < limit)
10,521✔
480
                    limit = l;
10,521✔
481
            }
21,003✔
482
        }
18,891✔
483
        QueryStateFindAll<std::vector<ObjKey>> st(m_key_values, limit);
18,285✔
484
        m_query->do_find_all(st);
18,285✔
485
    }
9,456✔
486

18,891✔
487
    apply_descriptors(m_descriptor_ordering);
9,456✔
488

9,456✔
489
    get_dependencies(m_last_seen_versions);
9,456✔
490
}
9,456✔
491

18,891✔
492
void TableView::apply_descriptors(const DescriptorOrdering& ordering)
9,456✔
493
{
18,891✔
494
    if (ordering.is_empty())
18,891✔
495
        return;
2,112✔
496
    size_t sz = size();
2,112✔
497
    if (sz == 0)
1,884✔
498
        return;
1,884✔
499

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

2,147,496,901✔
505
    auto apply_indexpairs = [&] {
16,377✔
506
        m_key_values.clear();
16,377✔
507
        for (auto& pair : index_pairs) {
2,147,496,901✔
508
            m_key_values.add(pair.key_for_object);
509
        }
510
        for (size_t t = 0; t < detached_ref_count; ++t)
2,598✔
511
            m_key_values.add(null_key);
2,598✔
512
        using_indexpairs = false;
6✔
513
    };
6✔
514

2,592✔
515
    auto use_indexpairs = [&] {
6✔
516
        index_pairs.reserve(sz);
6✔
517
        index_pairs.clear();
2,586✔
518
        // always put any detached refs at the end of the sort
6✔
519
        // FIXME: reconsider if this is the right thing to do
6✔
520
        // FIXME: consider specialized implementations in derived classes
2,580✔
521
        // (handling detached refs is not required in linkviews)
66✔
522
        for (size_t t = 0; t < sz; t++) {
66✔
523
            ObjKey key = get_key(t);
2,514✔
524
            if (m_table->is_valid(key)) {
2,514✔
525
                index_pairs.emplace_back(key, t);
2,514✔
526
            }
2,514✔
527
            else
2,598✔
528
                ++detached_ref_count;
529
        }
530
        using_indexpairs = true;
531
    };
532

533
    const int num_descriptors = int(ordering.size());
534
    for (int desc_ndx = 0; desc_ndx < num_descriptors; ++desc_ndx) {
535
        const BaseDescriptor* base_descr = ordering[desc_ndx];
536
        const BaseDescriptor* next = ((desc_ndx + 1) < num_descriptors) ? ordering[desc_ndx + 1] : nullptr;
537

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

545
            BaseDescriptor::Sorter predicate = base_descr->sorter(*m_table, index_pairs);
546

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

552
            base_descr->execute(index_pairs, predicate, next);
553
        }
554
        else {
555
            if (using_indexpairs) {
556
                apply_indexpairs();
557
            }
558
            base_descr->execute(*m_table, m_key_values, next);
559
            sz = size();
560
        }
561
    }
562
    // Apply the results
563
    if (using_indexpairs) {
564
        apply_indexpairs();
565
    }
566
}
567

568
bool TableView::is_in_table_order() const
569
{
570
    if (!m_table) {
571
        return false;
572
    }
573
    else if (m_collection_source) {
574
        return false;
575
    }
576
    else if (m_source_column_key) {
577
        return false;
578
    }
579
    else if (!m_query) {
580
        return false;
581
    }
582
    else {
583
        m_query->m_table.check();
584
        return m_query->produces_results_in_table_order() && !m_descriptor_ordering.will_apply_sort();
585
    }
586
}
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