couchbase 3.2.4 → 3.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. package/binding.gyp +5 -0
  2. package/deps/lcb/CMakeLists.txt +28 -6
  3. package/deps/lcb/README.markdown +5 -9
  4. package/deps/lcb/RELEASE_NOTES.markdown +80 -5
  5. package/deps/lcb/cmake/Modules/GetVersionInfo.cmake +1 -1
  6. package/deps/lcb/doc/Doxyfile +1 -1
  7. package/deps/lcb/doc/cbc.markdown +10 -0
  8. package/deps/lcb/gyp_config/common/libcouchbase/configuration.h +3 -3
  9. package/deps/lcb/include/libcouchbase/couchbase.h +52 -0
  10. package/deps/lcb/include/libcouchbase/error.h +5 -2
  11. package/deps/lcb/libcouchbase.gyp +7 -1
  12. package/deps/lcb/packaging/rpm/libcouchbase.spec.in +1 -1
  13. package/deps/lcb/plugins/io/iocp/iocp_iops.h +1 -1
  14. package/deps/lcb/plugins/io/iocp/iocp_loop.c +3 -3
  15. package/deps/lcb/plugins/io/iocp/iocp_util.c +2 -2
  16. package/deps/lcb/src/bucketconfig/bc_file.cc +29 -15
  17. package/deps/lcb/src/capi/cmd_counter.hh +12 -0
  18. package/deps/lcb/src/capi/cmd_exists.hh +12 -0
  19. package/deps/lcb/src/capi/cmd_get.hh +12 -0
  20. package/deps/lcb/src/capi/cmd_get_replica.hh +14 -1
  21. package/deps/lcb/src/capi/cmd_query.cc +13 -0
  22. package/deps/lcb/src/capi/cmd_query.hh +22 -14
  23. package/deps/lcb/src/capi/cmd_remove.hh +12 -0
  24. package/deps/lcb/src/capi/cmd_store.hh +12 -0
  25. package/deps/lcb/src/capi/cmd_subdoc.hh +12 -0
  26. package/deps/lcb/src/capi/cmd_touch.hh +12 -0
  27. package/deps/lcb/src/capi/cmd_unlock.hh +12 -0
  28. package/deps/lcb/src/capi/collection_qualifier.hh +4 -9
  29. package/deps/lcb/src/instance.cc +19 -0
  30. package/deps/lcb/src/internal.h +2 -1
  31. package/deps/lcb/src/mcserver/negotiate.cc +3 -0
  32. package/deps/lcb/src/n1ql/n1ql.cc +5 -1
  33. package/deps/lcb/src/n1ql/query_handle.cc +55 -30
  34. package/deps/lcb/src/n1ql/query_handle.hh +14 -2
  35. package/deps/lcb/src/operations/counter.cc +12 -0
  36. package/deps/lcb/src/operations/exists.cc +12 -0
  37. package/deps/lcb/src/operations/get.cc +12 -0
  38. package/deps/lcb/src/operations/get_replica.cc +18 -6
  39. package/deps/lcb/src/operations/ping.cc +2 -2
  40. package/deps/lcb/src/operations/remove.cc +12 -0
  41. package/deps/lcb/src/operations/store.cc +12 -0
  42. package/deps/lcb/src/operations/subdoc.cc +12 -0
  43. package/deps/lcb/src/operations/touch.cc +12 -0
  44. package/deps/lcb/src/operations/unlock.cc +12 -0
  45. package/deps/lcb/src/search/search_handle.cc +1 -2
  46. package/deps/lcb/src/settings.cc +1 -0
  47. package/deps/lcb/src/ssl/ssl_common.c +111 -22
  48. package/deps/lcb/src/utilities.cc +21 -0
  49. package/deps/lcb/src/utilities.h +3 -0
  50. package/deps/lcb/src/vbucket/vbucket.c +16 -7
  51. package/deps/lcb/tests/CMakeLists.txt +1 -1
  52. package/deps/lcb/tests/iotests/mock-environment.cc +13 -1
  53. package/deps/lcb/tests/iotests/mock-environment.h +3 -1
  54. package/deps/lcb/tests/iotests/serverparams.h +7 -2
  55. package/deps/lcb/tests/iotests/t_ratelimit.cc +739 -0
  56. package/deps/lcb/tests/iotests/testutil.cc +174 -0
  57. package/deps/lcb/tests/iotests/testutil.h +53 -0
  58. package/deps/lcb/tools/CMakeLists.txt +1 -1
  59. package/deps/lcb/tools/cbc-handlers.h +39 -0
  60. package/deps/lcb/tools/cbc-n1qlback.cc +1 -0
  61. package/deps/lcb/tools/cbc-pillowfight.cc +45 -35
  62. package/deps/lcb/tools/cbc.cc +31 -0
  63. package/deps/lcb/tools/docgen/docgen.h +11 -10
  64. package/dist/analyticsexecutor.js +2 -2
  65. package/dist/analyticsindexmanager.js +3 -3
  66. package/dist/binarycollection.d.ts +17 -0
  67. package/dist/binding.js +1 -1
  68. package/dist/bindingutilities.js +5 -1
  69. package/dist/bucketmanager.d.ts +1 -22
  70. package/dist/bucketmanager.js +5 -5
  71. package/dist/cluster.js +1 -1
  72. package/dist/collection.js +6 -6
  73. package/dist/collectionmanager.js +2 -2
  74. package/dist/connection.js +3 -3
  75. package/dist/connspec.js +5 -1
  76. package/dist/couchbase.js +5 -1
  77. package/dist/httpexecutor.d.ts +1 -0
  78. package/dist/httpexecutor.js +5 -1
  79. package/dist/logging.js +1 -1
  80. package/dist/queryexecutor.js +3 -3
  81. package/dist/searchindexmanager.js +1 -1
  82. package/dist/usermanager.js +2 -2
  83. package/dist/utilities.d.ts +1 -2
  84. package/dist/utilities.js +9 -2
  85. package/dist/viewexecutor.js +1 -1
  86. package/package.json +1 -1
  87. package/src/uv-plugin-all.cpp +1 -0
  88. package/dist/cas.d.ts +0 -0
  89. package/dist/cas.js +0 -1
@@ -127,6 +127,17 @@ struct lcb_CMDEXISTS_ {
127
127
  return LCB_SUCCESS;
128
128
  }
129
129
 
130
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
131
+ {
132
+ extra_privileges_.emplace_back(std::move(privilege));
133
+ return LCB_SUCCESS;
134
+ }
135
+
136
+ const std::vector<std::string> &extra_privileges() const
137
+ {
138
+ return extra_privileges_;
139
+ }
140
+
130
141
  bool want_impersonation() const
131
142
  {
132
143
  return !impostor_.empty();
@@ -145,6 +156,7 @@ struct lcb_CMDEXISTS_ {
145
156
  void *cookie_{nullptr};
146
157
  std::string key_{};
147
158
  std::string impostor_{};
159
+ std::vector<std::string> extra_privileges_{};
148
160
  };
149
161
 
150
162
  /**
@@ -186,6 +186,17 @@ struct lcb_CMDGET_ {
186
186
  return LCB_SUCCESS;
187
187
  }
188
188
 
189
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
190
+ {
191
+ extra_privileges_.emplace_back(std::move(privilege));
192
+ return LCB_SUCCESS;
193
+ }
194
+
195
+ const std::vector<std::string> &extra_privileges() const
196
+ {
197
+ return extra_privileges_;
198
+ }
199
+
189
200
  bool want_impersonation() const
190
201
  {
191
202
  return !impostor_.empty();
@@ -208,6 +219,7 @@ struct lcb_CMDGET_ {
208
219
  get_mode mode_{get_mode::normal};
209
220
  bool cookie_is_callback_{false};
210
221
  std::string impostor_{};
222
+ std::vector<std::string> extra_privileges_{};
211
223
  };
212
224
 
213
225
  /** @private */
@@ -60,7 +60,8 @@ struct lcb_CMDGETREPLICA_ {
60
60
  return LCB_SUCCESS;
61
61
  }
62
62
 
63
- int selected_replica_index() const {
63
+ int selected_replica_index() const
64
+ {
64
65
  return select_index_;
65
66
  }
66
67
 
@@ -162,6 +163,17 @@ struct lcb_CMDGETREPLICA_ {
162
163
  return LCB_SUCCESS;
163
164
  }
164
165
 
166
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
167
+ {
168
+ extra_privileges_.emplace_back(std::move(privilege));
169
+ return LCB_SUCCESS;
170
+ }
171
+
172
+ const std::vector<std::string> &extra_privileges() const
173
+ {
174
+ return extra_privileges_;
175
+ }
176
+
165
177
  bool want_impersonation() const
166
178
  {
167
179
  return !impostor_.empty();
@@ -182,6 +194,7 @@ struct lcb_CMDGETREPLICA_ {
182
194
  get_replica_mode mode_{get_replica_mode::any};
183
195
  int select_index_{0};
184
196
  std::string impostor_{};
197
+ std::vector<std::string> extra_privileges_{};
185
198
  };
186
199
 
187
200
  struct lcb_RESPGETREPLICA_ {
@@ -268,6 +268,11 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdquery_on_behalf_of(lcb_CMDQUERY *cmd, const c
268
268
  return cmd->on_behalf_of(std::string(data, data_len));
269
269
  }
270
270
 
271
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdquery_preserve_expiry(lcb_CMDQUERY *cmd, int preserve_expiry)
272
+ {
273
+ return cmd->preserve_expiry(preserve_expiry);
274
+ }
275
+
271
276
  LIBCOUCHBASE_API lcb_STATUS lcb_errctx_query_rc(const lcb_QUERY_ERROR_CONTEXT *ctx)
272
277
  {
273
278
  return ctx->rc;
@@ -287,6 +292,14 @@ LIBCOUCHBASE_API lcb_STATUS lcb_errctx_query_first_error_message(const lcb_QUERY
287
292
  return LCB_SUCCESS;
288
293
  }
289
294
 
295
+ LIBCOUCHBASE_API lcb_STATUS lcb_errctx_query_error_response_body(const lcb_QUERY_ERROR_CONTEXT *ctx, const char **body,
296
+ size_t *body_len)
297
+ {
298
+ *body = ctx->error_response_body;
299
+ *body_len = ctx->error_response_body_len;
300
+ return LCB_SUCCESS;
301
+ }
302
+
290
303
  LIBCOUCHBASE_API lcb_STATUS lcb_errctx_query_statement(const lcb_QUERY_ERROR_CONTEXT *ctx, const char **statement,
291
304
  size_t *statement_len)
292
305
  {
@@ -30,20 +30,22 @@
30
30
  */
31
31
  struct lcb_QUERY_ERROR_CONTEXT_ {
32
32
  lcb_STATUS rc;
33
- uint32_t first_error_code;
34
- const char *first_error_message;
35
- size_t first_error_message_len;
36
- const char *statement;
37
- size_t statement_len;
38
- const char *client_context_id;
39
- size_t client_context_id_len;
40
- const char *query_params;
41
- size_t query_params_len;
42
- uint32_t http_response_code;
43
- const char *http_response_message;
44
- size_t http_response_message_len;
45
- const char *endpoint;
46
- size_t endpoint_len;
33
+ uint32_t first_error_code{};
34
+ const char *first_error_message{};
35
+ size_t first_error_message_len{};
36
+ const char *error_response_body{};
37
+ size_t error_response_body_len{};
38
+ const char *statement{};
39
+ size_t statement_len{};
40
+ const char *client_context_id{};
41
+ size_t client_context_id_len{};
42
+ const char *query_params{};
43
+ size_t query_params_len{};
44
+ uint32_t http_response_code{};
45
+ const char *http_response_message{};
46
+ size_t http_response_message_len{};
47
+ const char *endpoint{};
48
+ size_t endpoint_len{};
47
49
  };
48
50
 
49
51
  /**
@@ -203,6 +205,12 @@ struct lcb_CMDQUERY_ {
203
205
  return LCB_SUCCESS;
204
206
  }
205
207
 
208
+ lcb_STATUS preserve_expiry(bool preserve_expiry)
209
+ {
210
+ root_["preserve_expiry"] = preserve_expiry;
211
+ return LCB_SUCCESS;
212
+ }
213
+
206
214
  lcb_STATUS callback(lcb_QUERY_CALLBACK row_callback)
207
215
  {
208
216
  callback_ = row_callback;
@@ -154,6 +154,17 @@ struct lcb_CMDREMOVE_ {
154
154
  return LCB_SUCCESS;
155
155
  }
156
156
 
157
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
158
+ {
159
+ extra_privileges_.emplace_back(std::move(privilege));
160
+ return LCB_SUCCESS;
161
+ }
162
+
163
+ const std::vector<std::string> &extra_privileges() const
164
+ {
165
+ return extra_privileges_;
166
+ }
167
+
157
168
  bool want_impersonation() const
158
169
  {
159
170
  return !impostor_.empty();
@@ -174,6 +185,7 @@ struct lcb_CMDREMOVE_ {
174
185
  std::uint64_t cas_{0};
175
186
  lcb_DURABILITY_LEVEL durability_level_{LCB_DURABILITYLEVEL_NONE};
176
187
  std::string impostor_{};
188
+ std::vector<std::string> extra_privileges_{};
177
189
  };
178
190
 
179
191
  /**
@@ -371,6 +371,17 @@ struct lcb_CMDSTORE_ {
371
371
  return LCB_SUCCESS;
372
372
  }
373
373
 
374
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
375
+ {
376
+ extra_privileges_.emplace_back(std::move(privilege));
377
+ return LCB_SUCCESS;
378
+ }
379
+
380
+ const std::vector<std::string> &extra_privileges() const
381
+ {
382
+ return extra_privileges_;
383
+ }
384
+
374
385
  bool want_impersonation() const
375
386
  {
376
387
  return !impostor_.empty();
@@ -402,6 +413,7 @@ struct lcb_CMDSTORE_ {
402
413
  bool cookie_is_callback_{false};
403
414
  bool preserve_expiry_{false};
404
415
  std::string impostor_{};
416
+ std::vector<std::string> extra_privileges_{};
405
417
  };
406
418
 
407
419
  /**
@@ -445,6 +445,17 @@ struct lcb_CMDSUBDOC_ {
445
445
  return LCB_SUCCESS;
446
446
  }
447
447
 
448
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
449
+ {
450
+ extra_privileges_.emplace_back(std::move(privilege));
451
+ return LCB_SUCCESS;
452
+ }
453
+
454
+ const std::vector<std::string> &extra_privileges() const
455
+ {
456
+ return extra_privileges_;
457
+ }
458
+
448
459
  bool want_impersonation() const
449
460
  {
450
461
  return !impostor_.empty();
@@ -469,6 +480,7 @@ struct lcb_CMDSUBDOC_ {
469
480
  lcb_SUBDOCSPECS_ specs_{};
470
481
  bool preserve_expiry_{false};
471
482
  std::string impostor_{};
483
+ std::vector<std::string> extra_privileges_{};
472
484
  };
473
485
 
474
486
  /**
@@ -138,6 +138,17 @@ struct lcb_CMDTOUCH_ {
138
138
  return LCB_SUCCESS;
139
139
  }
140
140
 
141
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
142
+ {
143
+ extra_privileges_.emplace_back(std::move(privilege));
144
+ return LCB_SUCCESS;
145
+ }
146
+
147
+ const std::vector<std::string> &extra_privileges() const
148
+ {
149
+ return extra_privileges_;
150
+ }
151
+
141
152
  bool want_impersonation() const
142
153
  {
143
154
  return !impostor_.empty();
@@ -157,6 +168,7 @@ struct lcb_CMDTOUCH_ {
157
168
  void *cookie_{nullptr};
158
169
  std::string key_{};
159
170
  std::string impostor_{};
171
+ std::vector<std::string> extra_privileges_{};
160
172
  };
161
173
 
162
174
  /**
@@ -141,6 +141,17 @@ struct lcb_CMDUNLOCK_ {
141
141
  return LCB_SUCCESS;
142
142
  }
143
143
 
144
+ lcb_STATUS on_behalf_of_add_extra_privilege(std::string privilege)
145
+ {
146
+ extra_privileges_.emplace_back(std::move(privilege));
147
+ return LCB_SUCCESS;
148
+ }
149
+
150
+ const std::vector<std::string> &extra_privileges() const
151
+ {
152
+ return extra_privileges_;
153
+ }
154
+
144
155
  bool want_impersonation() const
145
156
  {
146
157
  return !impostor_.empty();
@@ -160,6 +171,7 @@ struct lcb_CMDUNLOCK_ {
160
171
  std::string key_{};
161
172
  std::uint64_t cas_{};
162
173
  std::string impostor_{};
174
+ std::vector<std::string> extra_privileges_{};
163
175
  };
164
176
 
165
177
  /**
@@ -21,7 +21,6 @@
21
21
  #include <cstddef>
22
22
  #include <cstdint>
23
23
  #include <string>
24
- #include <sstream>
25
24
  #include <stdexcept>
26
25
 
27
26
  namespace lcb
@@ -48,11 +47,10 @@ struct collection_qualifier {
48
47
  if (collection_name != nullptr && collection_name_len > 0) {
49
48
  collection_.assign(collection_name, collection_name_len);
50
49
  }
51
- std::stringstream ss;
52
- ss << (scope_.empty() ? "_default" : scope_);
53
- ss << '.';
54
- ss << (collection_.empty() ? "_default" : collection_);
55
- spec_ = ss.str();
50
+
51
+ spec_ = (scope_.empty() ? "_default" : scope_) +
52
+ '.' +
53
+ (collection_.empty() ? "_default" : collection_);
56
54
  }
57
55
 
58
56
  const std::string &scope() const
@@ -124,9 +122,6 @@ struct collection_qualifier {
124
122
  /* nullptr/0 for collection is mapped to default collection */
125
123
  return true;
126
124
  }
127
- if (element_len < 1 || element_len > 30) {
128
- return false;
129
- }
130
125
  for (size_t i = 0; i < element_len; ++i) {
131
126
  if (!is_valid_collection_char(element[i])) {
132
127
  return false;
@@ -466,6 +466,25 @@ lcb_STATUS lcb_create(lcb_INSTANCE **instance, const lcb_CREATEOPTS *options)
466
466
  goto GT_DONE;
467
467
  }
468
468
 
469
+ {
470
+ // Warn users if they attempt to use Capella without TLS being enabled.
471
+ bool is_capella = false;
472
+ static std::string suffix = "cloud.couchbase.com";
473
+ for (auto &node : spec.hosts()) {
474
+ auto pos = node.hostname.find(suffix);
475
+ if (pos != std::string::npos && pos + suffix.size() == node.hostname.size()) {
476
+ is_capella = true;
477
+ break;
478
+ }
479
+ }
480
+
481
+ if (is_capella && (spec.sslopts() & LCB_SSL_ENABLED) == 0) {
482
+ lcb_log(LOGARGS(obj, INFO),
483
+ "TLS is required when connecting to Couchbase Capella. Please enable TLS by prefixing "
484
+ "the connection string with \"couchbases://\" (note the final 's').");
485
+ }
486
+ }
487
+
469
488
  if ((obj = (lcb_INSTANCE *)calloc(1, sizeof(*obj))) == nullptr) {
470
489
  err = LCB_ERR_NO_MEMORY;
471
490
  goto GT_DONE;
@@ -259,7 +259,8 @@ lcb_STATUS lcb_initialize_socket_subsystem(void);
259
259
  lcb_STATUS lcb_reinit(lcb_INSTANCE *obj, const char *connstr);
260
260
 
261
261
  lcb_RETRY_ACTION lcb_kv_should_retry(const lcb_settings *settings, const mc_PACKET *pkt, lcb_STATUS err);
262
- lcb_RETRY_ACTION lcb_query_should_retry(const lcb_settings *settings, lcb_QUERY_HANDLE *query, lcb_STATUS err);
262
+ lcb_RETRY_ACTION lcb_query_should_retry(const lcb_settings *settings, lcb_QUERY_HANDLE *query, lcb_STATUS err,
263
+ int retry_attribute);
263
264
 
264
265
  lcb_RESPCALLBACK lcb_find_callback(lcb_INSTANCE *instance, lcb_CALLBACK_TYPE cbtype);
265
266
 
@@ -660,6 +660,9 @@ GT_NEXT_PACKET:
660
660
  status);
661
661
  set_error(LCB_ERR_PROTOCOL_ERROR, "GET_ERRMAP response unexpected", &resp);
662
662
  }
663
+ if (settings->keypath) {
664
+ completed = !maybe_select_bucket();
665
+ }
663
666
  // Note, there is no explicit state transition here. LIST_MECHS is
664
667
  // pipelined after this request.
665
668
  break;
@@ -52,10 +52,14 @@ static lcb_RETRY_REASON query_code_to_reason(lcb_STATUS err)
52
52
  }
53
53
  }
54
54
 
55
- lcb_RETRY_ACTION lcb_query_should_retry(const lcb_settings *settings, lcb_QUERY_HANDLE *query, lcb_STATUS err)
55
+ lcb_RETRY_ACTION lcb_query_should_retry(const lcb_settings *settings, lcb_QUERY_HANDLE *query, lcb_STATUS err,
56
+ int retry_attribute)
56
57
  {
57
58
  lcb_RETRY_ACTION retry_action{};
58
59
  lcb_RETRY_REASON retry_reason = query_code_to_reason(err);
60
+ if (retry_attribute) {
61
+ retry_reason = LCB_RETRY_REASON_QUERY_ERROR_RETRYABLE;
62
+ }
59
63
  if (err == LCB_ERR_TIMEOUT) {
60
64
  /* We can't exceed a timeout for ETIMEDOUT */
61
65
  retry_action.should_retry = 0;
@@ -95,8 +95,8 @@ static void prepare_rowcb(lcb_INSTANCE *instance, int, const lcb_RESPQUERY *row)
95
95
 
96
96
  bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &rc)
97
97
  {
98
- first_error_message.clear();
99
- first_error_code = 0;
98
+ first_error.message.clear();
99
+ first_error.code = 0;
100
100
 
101
101
  Json::Value meta;
102
102
  if (!Json::Reader(Json::Features::strictMode()).parse(row, row + row_len, meta)) {
@@ -105,22 +105,42 @@ bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &
105
105
  const Json::Value &errors = meta["errors"];
106
106
  if (errors.isArray() && !errors.empty()) {
107
107
  const Json::Value &err = errors[0];
108
+ if (err.isMember("retry") && err["retry"].isBool()) {
109
+ first_error.retry = err["retry"].asBool();
110
+ }
111
+ if (err.isMember("reason") && err["reason"].isObject()) {
112
+ const Json::Value &reason = err["reason"];
113
+ if (reason.isMember("code") && reason["code"].isNumeric()) {
114
+ first_error.reason_code = reason["code"].asInt();
115
+ }
116
+ }
108
117
  const Json::Value &msg = err["msg"];
109
118
  if (msg.isString()) {
110
- first_error_message = msg.asString();
119
+ first_error.message = msg.asString();
111
120
  }
112
121
  const Json::Value &code = err["code"];
113
122
  if (code.isNumeric()) {
114
- first_error_code = code.asUInt();
115
- switch (first_error_code) {
123
+ first_error.code = code.asUInt();
124
+ switch (first_error.code) {
116
125
  case 3000:
117
126
  rc = LCB_ERR_PARSING_FAILURE;
118
127
  break;
119
128
  case 12009:
120
129
  rc = LCB_ERR_DML_FAILURE;
121
- if (first_error_message.find("CAS mismatch") != std::string::npos) {
130
+ if (first_error.message.find("CAS mismatch") != std::string::npos) {
122
131
  rc = LCB_ERR_CAS_MISMATCH;
123
132
  }
133
+ switch (first_error.reason_code) {
134
+ case 12033:
135
+ rc = LCB_ERR_CAS_MISMATCH;
136
+ break;
137
+ case 17014:
138
+ rc = LCB_ERR_DOCUMENT_NOT_FOUND;
139
+ break;
140
+ case 17012:
141
+ rc = LCB_ERR_DOCUMENT_EXISTS;
142
+ break;
143
+ }
124
144
  break;
125
145
  case 4040:
126
146
  case 4050:
@@ -132,31 +152,34 @@ bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &
132
152
  break;
133
153
  case 4300:
134
154
  rc = LCB_ERR_PLANNING_FAILURE;
135
- if (!first_error_message.empty()) {
155
+ if (!first_error.message.empty()) {
136
156
  std::regex already_exists("index.+already exists");
137
- if (std::regex_search(first_error_message, already_exists)) {
157
+ if (std::regex_search(first_error.message, already_exists)) {
138
158
  rc = LCB_ERR_INDEX_EXISTS;
139
159
  }
140
160
  }
141
161
  break;
142
162
  case 5000:
143
163
  rc = LCB_ERR_INTERNAL_SERVER_FAILURE;
144
- if (!first_error_message.empty()) {
164
+ if (!first_error.message.empty()) {
145
165
  std::regex already_exists("Index.+already exists"); /* NOTE: case sensitive */
146
166
  std::regex not_found("index.+not found");
147
- if (std::regex_search(first_error_message, already_exists)) {
167
+ if (std::regex_search(first_error.message, already_exists)) {
148
168
  rc = LCB_ERR_INDEX_EXISTS;
149
- } else if (std::regex_search(first_error_message, not_found)) {
169
+ } else if (std::regex_search(first_error.message, not_found)) {
150
170
  rc = LCB_ERR_INDEX_NOT_FOUND;
151
- } else if (first_error_message.find(
171
+ } else if (first_error.message.find(
152
172
  "Limit for number of indexes that can be created per scope has been reached") !=
153
173
  std::string::npos) {
154
174
  rc = LCB_ERR_QUOTA_LIMITED;
155
175
  }
156
176
  }
157
177
  break;
158
- case 12004:
159
178
  case 12016:
179
+ /* see MB-50643 */
180
+ first_error.retry = false;
181
+ /* fallthrough */
182
+ case 12004:
160
183
  rc = LCB_ERR_INDEX_NOT_FOUND;
161
184
  break;
162
185
  case 12003:
@@ -177,14 +200,14 @@ bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &
177
200
  break;
178
201
 
179
202
  default:
180
- if (first_error_code >= 4000 && first_error_code < 5000) {
203
+ if (first_error.code >= 4000 && first_error.code < 5000) {
181
204
  rc = LCB_ERR_PLANNING_FAILURE;
182
- } else if (first_error_code >= 5000 && first_error_code < 6000) {
205
+ } else if (first_error.code >= 5000 && first_error.code < 6000) {
183
206
  rc = LCB_ERR_INTERNAL_SERVER_FAILURE;
184
- } else if (first_error_code >= 10000 && first_error_code < 11000) {
207
+ } else if (first_error.code >= 10000 && first_error.code < 11000) {
185
208
  rc = LCB_ERR_AUTHENTICATION_FAILURE;
186
- } else if ((first_error_code >= 12000 && first_error_code < 13000) ||
187
- (first_error_code >= 14000 && first_error_code < 15000)) {
209
+ } else if ((first_error.code >= 12000 && first_error.code < 13000) ||
210
+ (first_error.code >= 14000 && first_error.code < 15000)) {
188
211
  rc = LCB_ERR_INDEX_FAILURE;
189
212
  }
190
213
  break;
@@ -218,11 +241,13 @@ void lcb_QUERY_HANDLE_::invoke_row(lcb_RESPQUERY *resp, bool is_last)
218
241
  resp->row = static_cast<const char *>(meta_buf.iov_base);
219
242
  resp->nrow = meta_buf.iov_len;
220
243
  parse_meta(resp->row, resp->nrow, resp->ctx.rc);
221
- if (!first_error_message.empty()) {
222
- resp->ctx.first_error_message = first_error_message.c_str();
223
- resp->ctx.first_error_message_len = first_error_message.size();
244
+ resp->ctx.error_response_body = resp->row;
245
+ resp->ctx.error_response_body_len = resp->nrow;
246
+ if (!first_error.message.empty()) {
247
+ resp->ctx.first_error_message = first_error.message.c_str();
248
+ resp->ctx.first_error_message_len = first_error.message.size();
224
249
  }
225
- resp->ctx.first_error_code = first_error_code;
250
+ resp->ctx.first_error_code = first_error.code;
226
251
  if (span_ != nullptr) {
227
252
  lcb::trace::finish_http_span(span_, this);
228
253
  span_ = nullptr;
@@ -358,27 +383,27 @@ lcb_RETRY_ACTION lcb_QUERY_HANDLE_::has_retriable_error(lcb_STATUS &rc)
358
383
  const uint32_t default_backoff = 100 /* ms */;
359
384
  if (rc == LCB_ERR_PREPARED_STATEMENT_FAILURE) {
360
385
  lcb_log(LOGARGS(this, TRACE), LOGFMT "Will retry request. rc: %s, code: %d, msg: %s", LOGID(this),
361
- lcb_strerror_short(rc), first_error_code, first_error_message.c_str());
386
+ lcb_strerror_short(rc), first_error.code, first_error.message.c_str());
362
387
  return {1, default_backoff};
363
388
  }
364
- if (first_error_code == 13014 &&
389
+ if (first_error.code == 13014 &&
365
390
  LCBT_SETTING(instance_, auth)->mode() == LCBAUTH_MODE_DYNAMIC) { // datastore.couchbase.insufficient_credentials
366
391
  auto result = request_credentials(LCBAUTH_REASON_AUTHENTICATION_FAILURE);
367
392
  bool credentials_found = result == LCBAUTH_RESULT_OK;
368
393
  lcb_log(LOGARGS(this, TRACE),
369
394
  LOGFMT "Invalidate credentials and retry request. creds: %s, rc: %s, code: %d, msg: %s", LOGID(this),
370
- credentials_found ? "ok" : "not_found", lcb_strerror_short(rc), first_error_code,
371
- first_error_message.c_str());
395
+ credentials_found ? "ok" : "not_found", lcb_strerror_short(rc), first_error.code,
396
+ first_error.message.c_str());
372
397
  return {credentials_found, default_backoff};
373
398
  }
374
- if (!first_error_message.empty()) {
399
+ if (!first_error.message.empty()) {
375
400
  for (const auto &magic_string : wtf_magic_strings) {
376
- if (first_error_message.find(magic_string) != std::string::npos) {
401
+ if (first_error.message.find(magic_string) != std::string::npos) {
377
402
  lcb_log(LOGARGS(this, TRACE),
378
403
  LOGFMT
379
404
  "Special error message detected. Will retry request. rc: %s (update to %s), code: %d, msg: %s",
380
405
  LOGID(this), lcb_strerror_short(rc), lcb_strerror_short(LCB_ERR_PREPARED_STATEMENT_FAILURE),
381
- first_error_code, first_error_message.c_str());
406
+ first_error.code, first_error.message.c_str());
382
407
  rc = LCB_ERR_PREPARED_STATEMENT_FAILURE;
383
408
  return {1, default_backoff};
384
409
  }
@@ -388,7 +413,7 @@ lcb_RETRY_ACTION lcb_QUERY_HANDLE_::has_retriable_error(lcb_STATUS &rc)
388
413
  if (rc == LCB_SUCCESS) {
389
414
  return {0, 0};
390
415
  }
391
- return lcb_query_should_retry(instance_->settings, this, rc);
416
+ return lcb_query_should_retry(instance_->settings, this, rc, first_error.retry);
392
417
  }
393
418
 
394
419
  lcb_STATUS lcb_QUERY_HANDLE_::issue_htreq(const std::string &body)
@@ -27,6 +27,19 @@
27
27
  #include "capi/cmd_query.hh"
28
28
  #include "query_cache.hh"
29
29
 
30
+ /**
31
+ * @private
32
+ */
33
+ namespace lcb
34
+ {
35
+ struct query_error {
36
+ std::string message{};
37
+ uint32_t code{};
38
+ bool retry{false};
39
+ uint32_t reason_code{0};
40
+ };
41
+ } // namespace lcb
42
+
30
43
  /**
31
44
  * @private
32
45
  */
@@ -296,8 +309,7 @@ struct lcb_QUERY_HANDLE_ : lcb::jsparse::Parser::Actions {
296
309
  /** String of the original statement. Cached here to avoid jsoncpp lookups */
297
310
  std::string statement_;
298
311
  std::string client_context_id_;
299
- std::string first_error_message{};
300
- uint32_t first_error_code{};
312
+ lcb::query_error first_error{};
301
313
 
302
314
  /** Whether we're retrying this */
303
315
  int retries_{0};
@@ -141,6 +141,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdcounter_on_behalf_of(lcb_CMDCOUNTER *cmd, con
141
141
  return cmd->on_behalf_of(std::string(data, data_len));
142
142
  }
143
143
 
144
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdcounter_on_behalf_of_extra_privilege(lcb_CMDCOUNTER *cmd, const char *privilege,
145
+ size_t privilege_len)
146
+ {
147
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
148
+ }
149
+
144
150
  static lcb_STATUS counter_validate(lcb_INSTANCE *instance, const lcb_CMDCOUNTER *cmd)
145
151
  {
146
152
  if (cmd->key().empty()) {
@@ -184,6 +190,12 @@ static lcb_STATUS counter_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_C
184
190
  if (err != LCB_SUCCESS) {
185
191
  return err;
186
192
  }
193
+ for (const auto &privilege : cmd->extra_privileges()) {
194
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
195
+ if (err != LCB_SUCCESS) {
196
+ return err;
197
+ }
198
+ }
187
199
  }
188
200
 
189
201
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -112,6 +112,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdexists_on_behalf_of(lcb_CMDEXISTS *cmd, const
112
112
  return cmd->on_behalf_of(std::string(data, data_len));
113
113
  }
114
114
 
115
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdexists_on_behalf_of_extra_privilege(lcb_CMDEXISTS *cmd, const char *privilege,
116
+ size_t privilege_len)
117
+ {
118
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
119
+ }
120
+
115
121
  static lcb_STATUS exists_validate(lcb_INSTANCE *instance, const lcb_CMDEXISTS *cmd)
116
122
  {
117
123
  if (cmd->key().empty()) {
@@ -139,6 +145,12 @@ static lcb_STATUS exists_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
139
145
  if (err != LCB_SUCCESS) {
140
146
  return err;
141
147
  }
148
+ for (const auto &privilege : cmd->extra_privileges()) {
149
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
150
+ if (err != LCB_SUCCESS) {
151
+ return err;
152
+ }
153
+ }
142
154
  }
143
155
 
144
156
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;