couchbase 3.2.4 → 3.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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;