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

realm / realm-core / github_pull_request_281922

31 Oct 2023 09:13AM UTC coverage: 90.445% (-0.08%) from 90.528%
github_pull_request_281922

Pull #7039

Evergreen

jedelbo
Merge branch 'next-major' into je/global-key
Pull Request #7039: Remove ability to synchronize objects without primary key

95324 of 175822 branches covered (0.0%)

101 of 105 new or added lines in 13 files covered. (96.19%)

238 existing lines in 19 files now uncovered.

232657 of 257235 relevant lines covered (90.45%)

6351359.67 hits per line

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

0.0
/src/realm/global_key.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2019 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/global_key.hpp>
20
#include <realm/string_data.hpp>
21
#include <realm/mixed.hpp>
22
#include <realm/util/sha_crypto.hpp>
23
#include <iomanip>
24
#include <ostream>
25
#include <istream>
26
#include <sstream>
27
#include <cctype>
28

29
namespace realm {
30

31
std::ostream& operator<<(std::ostream& os, const GlobalKey& object_id)
UNCOV
32
{
×
UNCOV
33
    return os << '{' << std::setw(4) << std::right << std::setfill('0') << std::hex << object_id.hi() << '-'
×
UNCOV
34
              << std::setw(4) << std::right << std::setfill('0') << std::hex << object_id.lo() << '}'
×
UNCOV
35
              << std::setfill(' ') << std::setw(0);
×
UNCOV
36
}
×
37

38
std::istream& operator>>(std::istream& in, GlobalKey& object_id)
UNCOV
39
{
×
UNCOV
40
    try {
×
UNCOV
41
        std::istream::sentry sentry{in};
×
UNCOV
42
        if (REALM_LIKELY(sentry)) {
×
UNCOV
43
            std::string string;
×
UNCOV
44
            char ch;
×
UNCOV
45
            in.get(ch);
×
UNCOV
46
            while (REALM_LIKELY(in)) {
×
UNCOV
47
                string.push_back(ch); // Throws
×
UNCOV
48
                if (REALM_LIKELY(ch == '}'))
×
UNCOV
49
                    break;
×
UNCOV
50
                in.get(ch);
×
UNCOV
51
            }
×
UNCOV
52
            object_id = GlobalKey::from_string(string);
×
UNCOV
53
        }
×
UNCOV
54
    }
×
UNCOV
55
    catch (const InvalidArgument&) {
×
UNCOV
56
        object_id = GlobalKey();
×
UNCOV
57
        in.setstate(std::ios_base::failbit);
×
UNCOV
58
    }
×
UNCOV
59
    return in;
×
UNCOV
60
}
×
61
std::string GlobalKey::to_string() const
UNCOV
62
{
×
UNCOV
63
    std::ostringstream ss;
×
UNCOV
64
    ss << *this;
×
UNCOV
65
    return ss.str();
×
UNCOV
66
}
×
67

68

69
GlobalKey GlobalKey::from_string(StringData string)
UNCOV
70
{
×
UNCOV
71
    if (string.size() < 5) // Must be at least "{0-0}"
×
UNCOV
72
        throw InvalidArgument(ErrorCodes::InvalidArgument, "Invalid object ID.");
×
73

UNCOV
74
    const char* begin = string.data();
×
UNCOV
75
    const char* end = string.data() + string.size();
×
UNCOV
76
    const char* last = end - 1;
×
77

UNCOV
78
    if (*begin != '{' || *last != '}')
×
79
        throw InvalidArgument(ErrorCodes::InvalidArgument, "Invalid object ID.");
×
80

UNCOV
81
    auto dash_pos = std::find(begin, end, '-');
×
UNCOV
82
    if (dash_pos == end)
×
83
        throw InvalidArgument(ErrorCodes::InvalidArgument, "Invalid object ID.");
×
UNCOV
84
    size_t dash_index = dash_pos - begin;
×
85

UNCOV
86
    const char* hi_begin = begin + 1;
×
UNCOV
87
    const char* lo_begin = dash_pos + 1;
×
UNCOV
88
    size_t hi_len = dash_index - 1;
×
UNCOV
89
    size_t lo_len = string.size() - dash_index - 2;
×
90

UNCOV
91
    if (hi_len == 0 || hi_len > 16 || lo_len == 0 || lo_len > 16) {
×
UNCOV
92
        throw InvalidArgument(ErrorCodes::InvalidArgument, "Invalid object ID.");
×
UNCOV
93
    }
×
94

UNCOV
95
    auto isxdigit = static_cast<int (*)(int)>(std::isxdigit);
×
UNCOV
96
    if (!std::all_of(hi_begin, hi_begin + hi_len, isxdigit) || !std::all_of(lo_begin, lo_begin + lo_len, isxdigit)) {
×
UNCOV
97
        throw InvalidArgument(ErrorCodes::InvalidArgument, "Invalid object ID.");
×
UNCOV
98
    }
×
99

100
    // hi_begin and lo_begin do not need to be copied into a NUL-terminated
101
    // buffer because we have checked above that they are immediately followed
102
    // by '-' or '}' respectively, and std::strtoull guarantees that it will
103
    // stop processing when it reaches either of those characters.
UNCOV
104
    return GlobalKey(strtoull(hi_begin, nullptr, 16), strtoull(lo_begin, nullptr, 16));
×
UNCOV
105
}
×
106

107
GlobalKey::GlobalKey(Mixed pk)
UNCOV
108
{
×
UNCOV
109
    if (pk.is_null()) {
×
110
        // Choose {1, 0} as the object ID for NULL. This could just as well have been {0, 0},
111
        // but then the null-representation for string and integer primary keys would have to
112
        // be different, as {0, 0} is a valid object ID for a row with an integer primary key.
113
        // Therefore, in the interest of simplicity, {1, 0} is chosen to represent NULL for
114
        // both integer and string primary keys.
UNCOV
115
        m_hi = 1;
×
UNCOV
116
        m_lo = 0;
×
UNCOV
117
        return;
×
UNCOV
118
    }
×
119

UNCOV
120
    union {
×
UNCOV
121
        unsigned char buffer[20];
×
UNCOV
122
        struct {
×
UNCOV
123
            uint64_t lo;
×
UNCOV
124
            uint64_t hi;
×
UNCOV
125
        } oid;
×
UNCOV
126
    } outp;
×
127

UNCOV
128
    switch (pk.get_type()) {
×
UNCOV
129
        case type_String: {
×
UNCOV
130
            auto val = pk.get_string();
×
UNCOV
131
            util::sha1(val.data(), val.size(), outp.buffer);
×
UNCOV
132
            m_hi = outp.oid.hi;
×
UNCOV
133
            m_lo = outp.oid.lo;
×
UNCOV
134
            break;
×
135
        }
×
136

UNCOV
137
        case type_ObjectId: {
×
UNCOV
138
            union ObjectIdBuffer {
×
UNCOV
139
                ObjectIdBuffer() {}
×
UNCOV
140
                char buffer[sizeof(ObjectId)];
×
UNCOV
141
                ObjectId id;
×
UNCOV
142
            } inp;
×
UNCOV
143
            inp.id = pk.get<ObjectId>();
×
UNCOV
144
            util::sha1(inp.buffer, sizeof(ObjectId), outp.buffer);
×
UNCOV
145
            m_hi = outp.oid.hi;
×
UNCOV
146
            m_lo = outp.oid.lo;
×
UNCOV
147
            break;
×
148
        }
×
149

UNCOV
150
        case type_Int:
×
UNCOV
151
            m_hi = 0;
×
UNCOV
152
            m_lo = uint64_t(pk.get_int());
×
UNCOV
153
            break;
×
154

UNCOV
155
        case type_UUID: {
×
UNCOV
156
            union UUIDBuffer {
×
UNCOV
157
                UUIDBuffer() {}
×
UNCOV
158
                UUID::UUIDBytes id;
×
UNCOV
159
                struct {
×
UNCOV
160
                    uint64_t upper;
×
UNCOV
161
                    uint64_t lower;
×
UNCOV
162
                } values;
×
UNCOV
163
            } inp;
×
UNCOV
164
            inp.id = pk.get<UUID>().to_bytes();
×
UNCOV
165
            m_hi = inp.values.upper;
×
UNCOV
166
            m_lo = inp.values.lower;
×
UNCOV
167
            break;
×
168
        }
×
169
        default:
×
170
            m_hi = -1;
×
171
            m_lo = -1;
×
172
            break;
×
UNCOV
173
    }
×
UNCOV
174
}
×
175

176
} // namespace realm
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