Skip to content

Commit 956cf60

Browse files
committed
CXX-754 Radically simplify bsoncxx/mongocxx exceptions and error_codes
1 parent f4a89da commit 956cf60

32 files changed

+410
-967
lines changed

examples/mongocxx/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ set(MONGOCXX_EXAMPLES
2626
bulk_write.cpp
2727
create.cpp
2828
document_validation.cpp
29+
exception.cpp
2930
index.cpp
3031
query.cpp
3132
remove.cpp

examples/mongocxx/exception.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// Copyright 2015 MongoDB Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <cstdlib>
16+
#include <iostream>
17+
18+
#include <bsoncxx/builder/stream/document.hpp>
19+
#include <bsoncxx/json.hpp>
20+
#include <mongocxx/client.hpp>
21+
#include <mongocxx/exception/bulk_write_exception.hpp>
22+
#include <mongocxx/exception/error_code.hpp>
23+
#include <mongocxx/exception/server_error_code.hpp>
24+
#include <mongocxx/exception/logic_error.hpp>
25+
#include <mongocxx/exception/operation_exception.hpp>
26+
#include <mongocxx/instance.hpp>
27+
#include <mongocxx/uri.hpp>
28+
29+
using bsoncxx::builder::stream::close_document;
30+
using bsoncxx::builder::stream::document;
31+
using bsoncxx::builder::stream::finalize;
32+
using bsoncxx::builder::stream::open_document;
33+
34+
int main(int, char**) {
35+
mongocxx::instance inst{};
36+
mongocxx::client conn{mongocxx::uri{}};
37+
38+
// @begin: cpp-logic-error
39+
// Using an uninitialized collection throws a mongocxx::logic_error.
40+
// A mongocxx::logic_error is-a mongocxx::exception is-a std::system_error.
41+
mongocxx::collection coll;
42+
try {
43+
coll.name();
44+
} catch (const mongocxx::logic_error& e) {
45+
std::cout << "Using an uninitialized collection throws:" << std::endl;
46+
47+
// Local errors, like those generated by mis-use of the
48+
// library itself, exist in the mongocxx 'error_category'
49+
// object. This is to be distinguished from the mongocxx
50+
// 'server_error_category' object, which tracks errors
51+
// returned by the server.
52+
//
53+
// NOTE: At this time, the server_error_category has no
54+
// associated symbolic errors. You must use numeric codes to
55+
// understand the errors returned in this category. See below
56+
// for more discussion.
57+
if (e.code().category() != mongocxx::error_category()) {
58+
return EXIT_FAILURE;
59+
}
60+
61+
// We can compare the error_code to a known mongocxx::error_code.
62+
if (e.code() != mongocxx::error_code::k_invalid_collection_object) {
63+
return EXIT_FAILURE;
64+
}
65+
66+
std::cout << e.what() << std::endl << std::endl;
67+
}
68+
// @end: cpp-logic-error
69+
70+
// @begin: cpp-operation-exception
71+
// Renaming a collection that does not exist throws a mongocxx::operation_exception.
72+
// A mongocxx::operation_exception is-a mongocxx::exception is-a std::system_error.
73+
coll = conn["test"]["coll"];
74+
coll.drop();
75+
try {
76+
coll.rename("coll2");
77+
} catch (const mongocxx::operation_exception& e) {
78+
std::cout << "Renaming a collection that does not exist throws:" << std::endl;
79+
80+
// We expect this error to arise from the server
81+
if (e.code().category() != mongocxx::server_error_category()) {
82+
return EXIT_FAILURE;
83+
}
84+
85+
// We can compare the error_code to a known server side error
86+
// code number. Please see
87+
// https://github.com/mongodb/mongo/blob/master/src/mongo/base/error_codes.err
88+
// for details on the sort of error codes the server might
89+
// return. In this case, 26 means 'NamespaceNotFound'.
90+
//
91+
// NOTE: Due to a design flaw in the C driver which currently
92+
// is the underlying implementation of the C++11 driver, it is
93+
// not possible to reliably distinguish between error codes
94+
// generated locally by libmongoc, or error codes generated
95+
// remotely by the server. Clients of libmongocxx are
96+
// therefore required to interpret the code numerically and
97+
// contextually. When the C driver fixes its error handling
98+
// strategy, we will add symbolic codes for server errors, and
99+
// report local library errors from libmongoc in the
100+
// mongocxx::error_code enumeration.
101+
if (e.code().value() != 26) {
102+
return EXIT_FAILURE;
103+
}
104+
105+
std::cout << e.what() << std::endl;
106+
if (e.raw_server_error()) {
107+
std::cout << bsoncxx::to_json(*(e.raw_server_error())) << std::endl;
108+
}
109+
std::cout << std::endl;
110+
}
111+
// @end: cpp-operation-exception
112+
113+
// @begin: cpp-bulk-write-exception
114+
// Adding a document whose "_id" is already present throws a mongocxx::bulk_write_exception.
115+
// A mongocxx::bulk_write_exception is-a mongocxx::operation_exception is-a mongocxx::exception
116+
// is-a std::system_error.
117+
auto doc1 = document{} << "_id" << 1 << finalize;
118+
coll.insert_one(doc1.view());
119+
try {
120+
coll.insert_one(doc1.view());
121+
} catch (const mongocxx::bulk_write_exception& e) {
122+
std::cout << "Adding a document whose _id is already present throws:" << std::endl;
123+
124+
// We expect this error to arise from the server
125+
if (e.code().category() != mongocxx::server_error_category()) {
126+
return EXIT_FAILURE;
127+
}
128+
129+
// We can compare the error_code to a known server side error code number
130+
if (e.code().value() != 11000) {
131+
return EXIT_FAILURE;
132+
}
133+
134+
std::cout << e.what() << std::endl;
135+
if (e.raw_server_error()) {
136+
std::cout << "Raw server error:" << std::endl;
137+
std::cout << bsoncxx::to_json(*(e.raw_server_error())) << std::endl;
138+
}
139+
std::cout << std::endl;
140+
}
141+
// @end: cpp-bulk-write-exception
142+
143+
return EXIT_SUCCESS;
144+
}

src/bsoncxx/CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,10 @@ set(bsoncxx_sources
7777
document/element.cpp
7878
document/value.cpp
7979
document/view.cpp
80+
exception/error_code.cpp
8081
json.cpp
8182
oid.cpp
82-
private/error_category.cpp
83-
private/error_code.cpp
8483
private/itoa.cpp
85-
private/libbson_error.cpp
8684
string/view_or_value.cpp
8785
types.cpp
8886
types/value.cpp

src/bsoncxx/builder/core.cpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
#include <bsoncxx/exception/error_code.hpp>
2222
#include <bsoncxx/exception/exception.hpp>
23-
#include <bsoncxx/private/error_code.hpp>
2423
#include <bsoncxx/private/itoa.hpp>
2524
#include <bsoncxx/private/stack.hpp>
2625
#include <bsoncxx/stdx/string_view.hpp>
@@ -71,8 +70,7 @@ class core::impl {
7170

7271
bsoncxx::document::value steal_document() {
7372
if (_root_is_array) {
74-
throw bsoncxx::exception{
75-
make_error_code(error_code::k_cannot_perform_document_operation_on_array)};
73+
throw bsoncxx::exception{error_code::k_cannot_perform_document_operation_on_array};
7674
}
7775

7876
uint32_t buf_len;
@@ -84,8 +82,7 @@ class core::impl {
8482

8583
bsoncxx::array::value steal_array() {
8684
if (!_root_is_array) {
87-
throw bsoncxx::exception{
88-
make_error_code(error_code::k_cannot_perform_array_operation_on_document)};
85+
throw bsoncxx::exception{error_code::k_cannot_perform_array_operation_on_document};
8986
}
9087

9188
uint32_t buf_len;
@@ -123,7 +120,7 @@ class core::impl {
123120
_itoa_key = _stack.empty() ? _n++ : _stack.back().n++;
124121
_user_key_view = stdx::string_view{_itoa_key.c_str(), _itoa_key.length()};
125122
} else if (!_has_user_key) {
126-
throw bsoncxx::exception{make_error_code(error_code::k_need_key)};
123+
throw bsoncxx::exception{error_code::k_need_key};
127124
}
128125

129126
_has_user_key = false;
@@ -207,14 +204,14 @@ core::~core() = default;
207204

208205
void core::key_view(stdx::string_view key) {
209206
if (_impl->is_array()) {
210-
throw bsoncxx::exception{make_error_code(error_code::k_cannot_append_key_in_sub_array)};
207+
throw bsoncxx::exception{error_code::k_cannot_append_key_in_sub_array};
211208
}
212209
_impl->push_key(std::move(key));
213210
}
214211

215212
void core::key_owned(std::string key) {
216213
if (_impl->is_array()) {
217-
throw bsoncxx::exception{make_error_code(error_code::k_cannot_append_key_in_sub_array)};
214+
throw bsoncxx::exception{error_code::k_cannot_append_key_in_sub_array};
218215
}
219216
_impl->push_key(std::move(key));
220217
}
@@ -428,55 +425,55 @@ void core::append(const bsoncxx::types::value& value) {
428425

429426
void core::close_document() {
430427
if (_impl->is_array()) {
431-
throw bsoncxx::exception{make_error_code(error_code::k_cannot_close_document_in_sub_array)};
428+
throw bsoncxx::exception{error_code::k_cannot_close_document_in_sub_array};
432429
}
433430

434431
if (_impl->depth() == 0) {
435-
throw bsoncxx::exception{make_error_code(error_code::k_no_document_to_close)};
432+
throw bsoncxx::exception{error_code::k_no_document_to_close};
436433
}
437434

438435
_impl->pop_back();
439436
}
440437

441438
void core::close_array() {
442439
if (!_impl->is_array()) {
443-
throw bsoncxx::exception{make_error_code(error_code::k_cannot_close_array_in_sub_document)};
440+
throw bsoncxx::exception{error_code::k_cannot_close_array_in_sub_document};
444441
}
445442

446443
if (_impl->depth() == 0) {
447-
throw bsoncxx::exception{make_error_code(error_code::k_no_array_to_close)};
444+
throw bsoncxx::exception{error_code::k_no_array_to_close};
448445
}
449446

450447
_impl->pop_back();
451448
}
452449

453450
bsoncxx::document::view core::view_document() const {
454451
if (!_impl->is_viewable()) {
455-
throw bsoncxx::exception{make_error_code(error_code::k_unmatched_key_in_builder)};
452+
throw bsoncxx::exception{error_code::k_unmatched_key_in_builder};
456453
}
457454

458455
return bsoncxx::document::view(bson_get_data(_impl->root()), _impl->root()->len);
459456
}
460457

461458
bsoncxx::document::value core::extract_document() {
462459
if (!_impl->is_viewable()) {
463-
throw bsoncxx::exception{make_error_code(error_code::k_unmatched_key_in_builder)};
460+
throw bsoncxx::exception{error_code::k_unmatched_key_in_builder};
464461
}
465462

466463
return _impl->steal_document();
467464
}
468465

469466
bsoncxx::array::view core::view_array() const {
470467
if (!_impl->is_viewable()) {
471-
throw bsoncxx::exception{make_error_code(error_code::k_unmatched_key_in_builder)};
468+
throw bsoncxx::exception{error_code::k_unmatched_key_in_builder};
472469
}
473470

474471
return bsoncxx::array::view(bson_get_data(_impl->root()), _impl->root()->len);
475472
}
476473

477474
bsoncxx::array::value core::extract_array() {
478475
if (!_impl->is_viewable()) {
479-
throw bsoncxx::exception{make_error_code(error_code::k_unmatched_key_in_builder)};
476+
throw bsoncxx::exception{error_code::k_unmatched_key_in_builder};
480477
}
481478

482479
return _impl->steal_array();

src/bsoncxx/document/element.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include <bsoncxx/exception/error_code.hpp>
2323
#include <bsoncxx/exception/exception.hpp>
2424
#include <bsoncxx/json.hpp>
25-
#include <bsoncxx/private/error_code.hpp>
2625
#include <bsoncxx/types.hpp>
2726
#include <bsoncxx/types/value.hpp>
2827

@@ -35,11 +34,11 @@
3534
iter.next_off = _offset; \
3635
bson_iter_next(&iter)
3736

38-
#define BSONCXX_TYPE_CHECK(name) \
39-
do { \
40-
if (type() != bsoncxx::type::name) { \
41-
throw bsoncxx::exception{make_error_code(error_code::k_need_element_type_##name)}; \
42-
} \
37+
#define BSONCXX_TYPE_CHECK(name) \
38+
do { \
39+
if (type() != bsoncxx::type::name) { \
40+
throw bsoncxx::exception{error_code::k_need_element_type_##name}; \
41+
} \
4342
} while (0)
4443

4544
namespace bsoncxx {
@@ -76,7 +75,7 @@ void element::offset(std::uint32_t offset) {
7675

7776
bsoncxx::type element::type() const {
7877
if (_raw == nullptr) {
79-
throw bsoncxx::exception{make_error_code(error_code::k_unset_element)};
78+
throw bsoncxx::exception{error_code::k_unset_element};
8079
}
8180

8281
CITER;
@@ -85,7 +84,7 @@ bsoncxx::type element::type() const {
8584

8685
stdx::string_view element::key() const {
8786
if (_raw == nullptr) {
88-
throw bsoncxx::exception{make_error_code(error_code::k_unset_element)};
87+
throw bsoncxx::exception{error_code::k_unset_element};
8988
}
9089

9190
CITER;

0 commit comments

Comments
 (0)