couchbase 4.2.1 → 4.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. package/CMakeLists.txt +1 -0
  2. package/deps/couchbase-cxx-client/.gitmodules +3 -0
  3. package/deps/couchbase-cxx-client/.idea/misc.xml +1 -0
  4. package/deps/couchbase-cxx-client/.idea/vcs.xml +1 -0
  5. package/deps/couchbase-cxx-client/CMakeLists.txt +11 -1
  6. package/deps/couchbase-cxx-client/README.md +3 -3
  7. package/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake +4 -1
  8. package/deps/couchbase-cxx-client/cmake/VersionInfo.cmake +13 -1
  9. package/deps/couchbase-cxx-client/cmake/build_version.hxx.in +1 -0
  10. package/deps/couchbase-cxx-client/core/cluster.hxx +15 -5
  11. package/deps/couchbase-cxx-client/core/impl/build_deferred_query_indexes.cxx +17 -6
  12. package/deps/couchbase-cxx-client/core/impl/cluster.cxx +1 -1
  13. package/deps/couchbase-cxx-client/core/impl/collection_query_index_manager.cxx +93 -0
  14. package/deps/couchbase-cxx-client/core/impl/configuration_profiles_registry.cxx +11 -0
  15. package/deps/couchbase-cxx-client/core/impl/create_query_index.cxx +119 -0
  16. package/deps/couchbase-cxx-client/core/impl/drop_query_index.cxx +108 -0
  17. package/deps/couchbase-cxx-client/core/impl/get.cxx +1 -1
  18. package/deps/couchbase-cxx-client/core/impl/get_all_query_indexes.cxx +76 -0
  19. package/deps/couchbase-cxx-client/core/impl/query.cxx +5 -7
  20. package/deps/couchbase-cxx-client/core/impl/watch_query_indexes.cxx +168 -0
  21. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +15 -1
  22. package/deps/couchbase-cxx-client/core/logger/configuration.hxx +3 -0
  23. package/deps/couchbase-cxx-client/core/logger/level.hxx +21 -0
  24. package/deps/couchbase-cxx-client/core/logger/logger.hxx +4 -6
  25. package/deps/couchbase-cxx-client/core/meta/CMakeLists.txt +4 -2
  26. package/deps/couchbase-cxx-client/core/meta/features.hxx +31 -0
  27. package/deps/couchbase-cxx-client/core/meta/version.cxx +67 -5
  28. package/deps/couchbase-cxx-client/core/meta/version.hxx +12 -1
  29. package/deps/couchbase-cxx-client/core/metrics/CMakeLists.txt +4 -1
  30. package/deps/couchbase-cxx-client/core/metrics/logging_meter.cxx +46 -5
  31. package/deps/couchbase-cxx-client/core/metrics/logging_meter.hxx +10 -26
  32. package/deps/couchbase-cxx-client/core/operations/document_get_projected.cxx +3 -2
  33. package/deps/couchbase-cxx-client/core/operations/document_query.cxx +10 -12
  34. package/deps/couchbase-cxx-client/core/operations/document_query.hxx +1 -3
  35. package/deps/couchbase-cxx-client/core/operations/management/query_index_build.cxx +8 -14
  36. package/deps/couchbase-cxx-client/core/operations/management/query_index_build.hxx +2 -1
  37. package/deps/couchbase-cxx-client/core/operations/management/query_index_build_deferred.hxx +15 -8
  38. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.cxx +7 -14
  39. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.hxx +2 -0
  40. package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.cxx +11 -16
  41. package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.hxx +2 -0
  42. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.cxx +8 -12
  43. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.hxx +4 -3
  44. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.cxx +21 -12
  45. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.hxx +3 -2
  46. package/deps/couchbase-cxx-client/core/origin.hxx +1 -1
  47. package/deps/couchbase-cxx-client/core/platform/uuid.cc +1 -2
  48. package/deps/couchbase-cxx-client/core/protocol/cmd_hello.hxx +5 -1
  49. package/deps/couchbase-cxx-client/core/query_context.hxx +79 -0
  50. package/deps/couchbase-cxx-client/core/tracing/CMakeLists.txt +3 -1
  51. package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.cxx +19 -4
  52. package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.hxx +2 -2
  53. package/deps/couchbase-cxx-client/core/transactions/async_attempt_context.hxx +10 -4
  54. package/deps/couchbase-cxx-client/core/transactions/atr_cleanup_entry.cxx +52 -63
  55. package/deps/couchbase-cxx-client/core/transactions/attempt_context.hxx +8 -3
  56. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +163 -126
  57. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.hxx +24 -37
  58. package/deps/couchbase-cxx-client/core/transactions/forward_compat.hxx +4 -4
  59. package/deps/couchbase-cxx-client/core/transactions/internal/atr_cleanup_entry.hxx +51 -13
  60. package/deps/couchbase-cxx-client/core/transactions/internal/client_record.hxx +26 -1
  61. package/deps/couchbase-cxx-client/core/transactions/internal/doc_record.hxx +21 -0
  62. package/deps/couchbase-cxx-client/core/transactions/internal/logging.hxx +40 -18
  63. package/deps/couchbase-cxx-client/core/transactions/internal/transaction_context.hxx +5 -0
  64. package/deps/couchbase-cxx-client/core/transactions/result.hxx +26 -0
  65. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +48 -47
  66. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.hxx +6 -6
  67. package/deps/couchbase-cxx-client/core/transactions/transaction_context.cxx +33 -19
  68. package/deps/couchbase-cxx-client/core/transactions/transaction_get_result.hxx +18 -2
  69. package/deps/couchbase-cxx-client/core/transactions/transaction_links.hxx +25 -2
  70. package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +4 -4
  71. package/deps/couchbase-cxx-client/core/transactions/transactions_cleanup.cxx +49 -56
  72. package/deps/couchbase-cxx-client/core/transactions/waitable_op_list.hxx +7 -7
  73. package/deps/couchbase-cxx-client/core/transactions.hxx +0 -12
  74. package/deps/couchbase-cxx-client/core/utils/binary.hxx +1 -1
  75. package/deps/couchbase-cxx-client/core/utils/keyspace.hxx +55 -0
  76. package/deps/couchbase-cxx-client/couchbase/build_query_index_options.hxx +12 -45
  77. package/deps/couchbase-cxx-client/couchbase/cluster.hxx +1 -1
  78. package/deps/couchbase-cxx-client/couchbase/cluster_options.hxx +6 -7
  79. package/deps/couchbase-cxx-client/couchbase/collection.hxx +8 -0
  80. package/deps/couchbase-cxx-client/couchbase/collection_query_index_manager.hxx +218 -0
  81. package/deps/couchbase-cxx-client/couchbase/configuration_profiles_registry.hxx +3 -0
  82. package/deps/couchbase-cxx-client/couchbase/create_primary_query_index_options.hxx +166 -0
  83. package/deps/couchbase-cxx-client/couchbase/create_query_index_options.hxx +172 -0
  84. package/deps/couchbase-cxx-client/couchbase/drop_primary_query_index_options.hxx +129 -0
  85. package/deps/couchbase-cxx-client/couchbase/drop_query_index_options.hxx +116 -0
  86. package/deps/couchbase-cxx-client/couchbase/fmt/cas.hxx +1 -1
  87. package/deps/couchbase-cxx-client/couchbase/fmt/query_scan_consistency.hxx +46 -0
  88. package/deps/couchbase-cxx-client/couchbase/fmt/query_status.hxx +70 -0
  89. package/deps/couchbase-cxx-client/couchbase/fmt/tls_verify_mode.hxx +46 -0
  90. package/deps/couchbase-cxx-client/couchbase/get_all_query_indexes_options.hxx +100 -0
  91. package/deps/couchbase-cxx-client/{core → couchbase}/management/query_index.hxx +2 -2
  92. package/deps/couchbase-cxx-client/couchbase/metrics/meter.hxx +16 -0
  93. package/deps/couchbase-cxx-client/couchbase/query_index_manager.hxx +178 -6
  94. package/deps/couchbase-cxx-client/couchbase/query_options.hxx +1 -18
  95. package/deps/couchbase-cxx-client/couchbase/scope.hxx +5 -2
  96. package/deps/couchbase-cxx-client/couchbase/tracing/request_tracer.hxx +16 -0
  97. package/deps/couchbase-cxx-client/couchbase/transactions/async_attempt_context.hxx +11 -4
  98. package/deps/couchbase-cxx-client/couchbase/transactions/attempt_context.hxx +5 -3
  99. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_keyspace.hxx +16 -0
  100. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_query_options.hxx +0 -6
  101. package/deps/couchbase-cxx-client/couchbase/watch_query_indexes_options.hxx +115 -0
  102. package/deps/couchbase-cxx-client/examples/minimal.cxx +3 -1
  103. package/deps/couchbase-cxx-client/test/test_integration_crud.cxx +72 -0
  104. package/deps/couchbase-cxx-client/test/test_integration_management.cxx +727 -310
  105. package/deps/couchbase-cxx-client/test/test_integration_query.cxx +4 -8
  106. package/deps/couchbase-cxx-client/test/test_integration_transcoders.cxx +14 -0
  107. package/deps/couchbase-cxx-client/test/test_transaction_transaction_public_blocking_api.cxx +34 -19
  108. package/deps/couchbase-cxx-client/test/test_unit_transaction_logging.cxx +66 -22
  109. package/deps/couchbase-cxx-client/test/test_unit_utils.cxx +51 -0
  110. package/deps/couchbase-cxx-client/test/tools/tool_kv_loader.cxx +2 -2
  111. package/deps/couchbase-cxx-client/test/utils/integration_test_guard.cxx +2 -0
  112. package/deps/couchbase-cxx-client/test/utils/wait_until.cxx +4 -4
  113. package/deps/couchbase-cxx-client/third_party/docopt/.travis.yml +103 -0
  114. package/deps/couchbase-cxx-client/third_party/docopt/CMakeLists.txt +129 -0
  115. package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-Boost-1.0 +23 -0
  116. package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-MIT +23 -0
  117. package/deps/couchbase-cxx-client/third_party/docopt/README.rst +479 -0
  118. package/deps/couchbase-cxx-client/third_party/docopt/docopt-config.cmake +1 -0
  119. package/deps/couchbase-cxx-client/third_party/docopt/docopt.cpp +687 -0
  120. package/deps/couchbase-cxx-client/third_party/docopt/docopt.h +98 -0
  121. package/deps/couchbase-cxx-client/third_party/docopt/docopt.pc.in +9 -0
  122. package/deps/couchbase-cxx-client/third_party/docopt/docopt_private.h +676 -0
  123. package/deps/couchbase-cxx-client/third_party/docopt/docopt_util.h +122 -0
  124. package/deps/couchbase-cxx-client/third_party/docopt/docopt_value.h +341 -0
  125. package/deps/couchbase-cxx-client/third_party/docopt/examples/naval_fate.cpp +36 -0
  126. package/deps/couchbase-cxx-client/third_party/docopt/main.cpp +16 -0
  127. package/deps/couchbase-cxx-client/third_party/docopt/run_testcase.cpp +40 -0
  128. package/deps/couchbase-cxx-client/third_party/docopt/run_tests.py +72 -0
  129. package/deps/couchbase-cxx-client/third_party/docopt/testcases.docopt +957 -0
  130. package/deps/couchbase-cxx-client/tools/CMakeLists.txt +14 -0
  131. package/deps/couchbase-cxx-client/tools/cbc.cxx +65 -0
  132. package/deps/couchbase-cxx-client/tools/command.hxx +31 -0
  133. package/deps/couchbase-cxx-client/tools/command_registry.cxx +43 -0
  134. package/deps/couchbase-cxx-client/tools/command_registry.hxx +39 -0
  135. package/deps/couchbase-cxx-client/tools/get.cxx +267 -0
  136. package/deps/couchbase-cxx-client/tools/get.hxx +26 -0
  137. package/deps/couchbase-cxx-client/tools/query.cxx +441 -0
  138. package/deps/couchbase-cxx-client/tools/query.hxx +26 -0
  139. package/deps/couchbase-cxx-client/tools/utils.cxx +418 -0
  140. package/deps/couchbase-cxx-client/tools/utils.hxx +150 -0
  141. package/deps/couchbase-cxx-client/tools/version.cxx +82 -0
  142. package/deps/couchbase-cxx-client/tools/version.hxx +26 -0
  143. package/dist/authenticators.d.ts +2 -2
  144. package/dist/authenticators.js +1 -2
  145. package/dist/binding.d.ts +32 -16
  146. package/dist/cluster.js +14 -7
  147. package/dist/collection.d.ts +6 -0
  148. package/dist/collection.js +8 -0
  149. package/dist/queryexecutor.js +1 -1
  150. package/dist/queryindexmanager.d.ts +100 -4
  151. package/dist/queryindexmanager.js +344 -118
  152. package/dist/transactions.js +0 -2
  153. package/package.json +1 -1
  154. package/src/connection.cpp +2 -0
  155. package/src/connection.hpp +1 -0
  156. package/src/connection_autogen.cpp +16 -0
  157. package/src/jstocbpp_autogen.hpp +93 -23
  158. package/src/jstocbpp_basic.hpp +24 -0
  159. package/src/jstocbpp_transactions.hpp +0 -8
  160. package/tools/gen-bindings-js.js +1 -0
  161. package/tools/gen-bindings-json.py +4 -2
  162. package/deps/couchbase-cxx-client/core/transactions/logging.cxx +0 -107
@@ -0,0 +1,441 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2023-Present Couchbase, 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
+ #include "query.hxx"
19
+ #include "core/utils/binary.hxx"
20
+ #include "utils.hxx"
21
+
22
+ #include <core/logger/logger.hxx>
23
+ #include <couchbase/cluster.hxx>
24
+ #include <couchbase/fmt/query_status.hxx>
25
+
26
+ #include <asio/io_context.hpp>
27
+ #include <fmt/chrono.h>
28
+ #include <spdlog/fmt/bin_to_hex.h>
29
+ #include <tao/json.hpp>
30
+
31
+ #include <regex>
32
+
33
+ namespace cbc
34
+ {
35
+ namespace
36
+ {
37
+ static auto
38
+ usage() -> std::string
39
+ {
40
+ static const std::string default_bucket_name{ "default" };
41
+
42
+ static const std::string usage_string = fmt::format(
43
+ R"(Display version information.
44
+
45
+ Usage:
46
+ cbc query [options] <statement>...
47
+ cbc query [options] --param=NAME=VALUE... <statement>...
48
+ cbc query [options] --raw=NAME=VALUE... <statement>...
49
+ cbc query (-h|--help)
50
+
51
+ Options:
52
+ -h --help Show this screen.
53
+ --param=NAME=VALUE Parameters for the query. Without '=' sign value will be treated as positional parameter.
54
+ --prepare Prepare statement.
55
+ --read-only Mark query as read only. Any mutations will fail.
56
+ --preserve-expiry Ensure that expiry will be preserved after mutations.
57
+ --disable-metrics Do not request metrics.
58
+ --profile=MODE Request the service to profile the query and return report (allowed values: off, phases, timings).
59
+ --bucket-name=STRING Name of the bucket where the scope is defined (see --scope-name).
60
+ --scope-name=STRING Name of the scope.
61
+ --client-context-id=STRING Override client context ID for the query(-ies).
62
+ --flex-index Tell query service to utilize flex index (full text search).
63
+ --maximum-parallelism=INTEGER Parallelism for query execution (0 to disable).
64
+ --scan-cap=INTEGER Maximum buffer size between indexer and query service.
65
+ --scan-wait=DURATION How long query engine will wait for indexer to catch up on scan consistency.
66
+ --scan-consistency=MODE Set consistency guarantees for the query (allowed values: not_bounded, request_plus).
67
+ --pipeline-batch=INTEGER Number of items execution operators can batch for fetch from the Key/Value service.
68
+ --pipeline-cap=INTEGER Maximum number of items each execution operator can buffer between various operators.
69
+ --raw=NAME=VALUE Set any query option for the query. Read the documentation: https://docs.couchbase.com/server/current/n1ql/n1ql-rest-api.
70
+ --json-lines Use JSON Lines format (https://jsonlines.org/) to print results.
71
+
72
+ {logger_options}{cluster_options}
73
+
74
+ Examples:
75
+
76
+ 1. Query with positional parameters:
77
+
78
+ cbc query --param 1 --param 2 'SELECT $1 + $2'
79
+
80
+ 2. Query with named parameters:
81
+
82
+ cbc query --param a=1 --param b=2 'SELECT $a + $b'
83
+ )",
84
+ fmt::arg("logger_options", usage_block_for_logger()),
85
+ fmt::arg("cluster_options", usage_block_for_cluster_options()));
86
+
87
+ return usage_string;
88
+ }
89
+
90
+ struct console_output_options {
91
+ bool json_lines{ false };
92
+ };
93
+
94
+ struct scope_with_bucket {
95
+ std::string bucket_name;
96
+ std::string scope_name;
97
+ };
98
+
99
+ template<typename QueryEndpoint>
100
+ static auto
101
+ do_query(QueryEndpoint& endpoint, std::string statement, const couchbase::query_options& options)
102
+ {
103
+ return endpoint.query(std::move(statement), options);
104
+ }
105
+
106
+ static void
107
+ print_result_json_line(const std::optional<scope_with_bucket>& scope_id,
108
+ const std::string& statement,
109
+ const couchbase::query_error_context& ctx,
110
+ const couchbase::query_result& resp,
111
+ const couchbase::query_options& query_options)
112
+ {
113
+ auto built_options = query_options.build();
114
+
115
+ tao::json::value line = tao::json::empty_object;
116
+
117
+ tao::json::value meta = {
118
+ { "statement", statement },
119
+ };
120
+ if (scope_id) {
121
+ meta["bucket_name"] = scope_id->bucket_name;
122
+ meta["scope_name"] = scope_id->scope_name;
123
+ }
124
+ if (ctx.parameters()) {
125
+ try {
126
+ auto json = tao::json::from_string(ctx.parameters().value());
127
+ json.erase("statement");
128
+ meta["options"] = json;
129
+ } catch (const tao::pegtl::parse_error&) {
130
+ meta["options"] = ctx.parameters().value();
131
+ }
132
+ }
133
+
134
+ if (ctx.ec()) {
135
+ tao::json::value error = {
136
+ { "code", ctx.ec().value() },
137
+ { "message", ctx.ec().message() },
138
+ };
139
+ try {
140
+ error["body"] = tao::json::from_string(ctx.http_body());
141
+ } catch (const tao::pegtl::parse_error&) {
142
+ error["text"] = ctx.http_body();
143
+ }
144
+ line["error"] = error;
145
+ } else {
146
+ meta["status"] = fmt::format("{}", resp.meta_data().status());
147
+ meta["client_context_id"] = resp.meta_data().client_context_id();
148
+ meta["request_id"] = resp.meta_data().request_id();
149
+ if (const auto& signature = resp.meta_data().signature()) {
150
+ try {
151
+ meta["signature"] = couchbase::core::utils::json::parse_binary(signature.value());
152
+ } catch (const tao::pegtl::parse_error&) {
153
+ meta["signature"] = signature.value();
154
+ }
155
+ }
156
+ if (const auto& metrics = resp.meta_data().metrics(); metrics.has_value()) {
157
+ meta["metrics"] = {
158
+ { "elapsed_time", fmt::format("{}", metrics->elapsed_time()) },
159
+ { "execution_time", fmt::format("{}", metrics->execution_time()) },
160
+ { "result_count", metrics->result_count() },
161
+ { "result_size", metrics->result_size() },
162
+ { "sort_count", metrics->sort_count() },
163
+ { "mutation_count", metrics->mutation_count() },
164
+ { "error_count", metrics->error_count() },
165
+ { "warning_count", metrics->warning_count() },
166
+ };
167
+ }
168
+ if (const auto& profile = resp.meta_data().profile(); profile) {
169
+ try {
170
+ meta["profile"] = couchbase::core::utils::json::parse_binary(profile.value());
171
+ } catch (const tao::pegtl::parse_error&) {
172
+ meta["profile"] = profile.value();
173
+ }
174
+ }
175
+ if (!resp.meta_data().warnings().empty()) {
176
+ tao::json::value warnings = tao::json::empty_array;
177
+ for (const auto& item : resp.meta_data().warnings()) {
178
+ tao::json::value warning = {
179
+ { "message", item.message() },
180
+ { "code", item.code() },
181
+ };
182
+ if (item.reason()) {
183
+ warning["reason"] = item.reason().value();
184
+ }
185
+ if (item.retry()) {
186
+ warning["retry"] = item.retry().value();
187
+ }
188
+ warnings.emplace_back(warning);
189
+ }
190
+ meta["warnings"] = warnings;
191
+ }
192
+ tao::json::value rows = tao::json::empty_array;
193
+ for (const auto& row : resp.rows_as_binary()) {
194
+ try {
195
+ rows.emplace_back(couchbase::core::utils::json::parse_binary(row));
196
+ } catch (const tao::pegtl::parse_error&) {
197
+ rows.emplace_back(row);
198
+ }
199
+ }
200
+ line["rows"] = rows;
201
+ }
202
+ line["meta"] = meta;
203
+ fmt::print(stdout, "{}\n", tao::json::to_string<tao::json::events::binary_to_base64>(line));
204
+ fflush(stdout);
205
+ }
206
+
207
+ static void
208
+ print_result(const std::optional<scope_with_bucket>& scope_id,
209
+ const std::string& statement,
210
+ const couchbase::query_error_context& ctx,
211
+ const couchbase::query_result& resp,
212
+ const couchbase::query_options& query_options)
213
+ {
214
+ auto built_options = query_options.build();
215
+
216
+ auto header = fmt::memory_buffer();
217
+ if (scope_id) {
218
+ fmt::format_to(std::back_inserter(header), "bucket_name: {}, scope_name: {}", scope_id->bucket_name, scope_id->scope_name);
219
+ }
220
+ fmt::format_to(
221
+ std::back_inserter(header), "{}statement: \"{}\"", header.size() == 0 ? "" : ", ", tao::json::internal::escape(statement));
222
+
223
+ if (ctx.parameters()) {
224
+ try {
225
+ auto json = tao::json::from_string(ctx.parameters().value());
226
+ json.erase("statement");
227
+ fmt::format_to(std::back_inserter(header), ", options: {}", tao::json::to_string(json));
228
+ } catch (const tao::pegtl::parse_error&) {
229
+ fmt::format_to(std::back_inserter(header), ", options: {}", ctx.parameters().value());
230
+ }
231
+ }
232
+ fmt::print(stdout, "--- {}\n", std::string_view{ header.data(), header.size() });
233
+
234
+ if (ctx.ec()) {
235
+ fmt::print("ERROR. code: {}, message: {}, server: {} \"{}\")\n",
236
+ ctx.ec().value(),
237
+ ctx.ec().message(),
238
+ ctx.first_error_code(),
239
+ tao::json::internal::escape(ctx.first_error_message()));
240
+ if (!ctx.http_body().empty()) {
241
+ try {
242
+ fmt::print("{}\n", tao::json::to_string(tao::json::from_string(ctx.http_body())));
243
+ } catch (const tao::pegtl::parse_error&) {
244
+ fmt::print("{}\n", ctx.http_body());
245
+ }
246
+ }
247
+ } else {
248
+ auto meta = fmt::memory_buffer();
249
+ fmt::format_to(std::back_inserter(meta),
250
+ "status: {}, client_context_id: \"{}\", request_id: \"{}\"",
251
+ resp.meta_data().status(),
252
+ resp.meta_data().client_context_id(),
253
+ resp.meta_data().request_id());
254
+ if (const auto& metrics = resp.meta_data().metrics(); metrics.has_value()) {
255
+ fmt::format_to(std::back_inserter(meta),
256
+ ", elapsed: {}, execution: {}, result: {}, sort: {}, mutations: {}, errors: {}, warnings: {}",
257
+ metrics->elapsed_time(),
258
+ metrics->execution_time(),
259
+ metrics->result_count(),
260
+ metrics->sort_count(),
261
+ metrics->mutation_count(),
262
+ metrics->error_count(),
263
+ metrics->warning_count());
264
+ }
265
+ fmt::print(stdout, "{}\n", std::string_view{ meta.data(), meta.size() });
266
+ if (!resp.meta_data().warnings().empty()) {
267
+ for (const auto& item : resp.meta_data().warnings()) {
268
+ auto warning = fmt::memory_buffer();
269
+ fmt::format_to(std::back_inserter(warning), "WARNING. code: {}, message: \"{}\"\n", item.code(), item.message());
270
+ if (item.reason()) {
271
+ fmt::format_to(std::back_inserter(warning), ", reason: {}\n", item.reason().value());
272
+ }
273
+ if (item.retry()) {
274
+ fmt::format_to(std::back_inserter(warning), ", retry: {}\n", item.retry().value());
275
+ }
276
+ fmt::print(stdout, "{}\n", std::string_view{ warning.data(), warning.size() });
277
+ }
278
+ }
279
+ if (const auto& profile = resp.meta_data().profile(); profile) {
280
+ try {
281
+ fmt::print("{}\n", tao::json::to_string(couchbase::core::utils::json::parse_binary(profile.value()), 2));
282
+ } catch (const tao::pegtl::parse_error&) {
283
+ fmt::print("{:a}\n", spdlog::to_hex(profile.value()));
284
+ }
285
+ }
286
+ for (const auto& row : resp.rows_as_binary()) {
287
+ try {
288
+ fmt::print("{}\n", tao::json::to_string(couchbase::core::utils::json::parse_binary(row)));
289
+ } catch (const tao::pegtl::parse_error&) {
290
+ fmt::print("{:a}\n", spdlog::to_hex(row));
291
+ }
292
+ }
293
+ }
294
+ fflush(stdout);
295
+ }
296
+
297
+ static void
298
+ do_work(const std::string& connection_string,
299
+ couchbase::cluster_options& cluster_options,
300
+ const std::vector<std::string>& statements,
301
+ const std::optional<scope_with_bucket>& scope_id,
302
+ const couchbase::query_options& query_options,
303
+ const console_output_options& output_options)
304
+ {
305
+ asio::io_context io;
306
+ auto guard = asio::make_work_guard(io);
307
+ std::thread io_thread([&io]() { io.run(); });
308
+
309
+ auto [cluster, ec] = couchbase::cluster::connect(io, connection_string, cluster_options).get();
310
+ if (ec) {
311
+ throw std::system_error(ec);
312
+ }
313
+
314
+ std::optional<couchbase::scope> scope{};
315
+ if (scope_id) {
316
+ scope = cluster.bucket(scope_id->bucket_name).scope(scope_id->scope_name);
317
+ }
318
+
319
+ for (const auto& statement : statements) {
320
+ auto [ctx, resp] = (scope ? do_query(scope.value(), statement, query_options) : do_query(cluster, statement, query_options)).get();
321
+
322
+ if (output_options.json_lines) {
323
+ print_result_json_line(scope_id, statement, ctx, resp, query_options);
324
+ } else {
325
+ print_result(scope_id, statement, ctx, resp, query_options);
326
+ }
327
+ }
328
+
329
+ cluster.close();
330
+ guard.reset();
331
+
332
+ io_thread.join();
333
+ }
334
+ } // namespace
335
+
336
+ void
337
+ cbc::query::execute(const std::vector<std::string>& argv)
338
+ {
339
+ try {
340
+
341
+ auto options = cbc::parse_options(usage(), argv);
342
+ if (options["--help"].asBool()) {
343
+ fmt::print(stdout, usage());
344
+ return;
345
+ }
346
+
347
+ cbc::apply_logger_options(options);
348
+
349
+ couchbase::cluster_options cluster_options{ cbc::default_cluster_options() };
350
+ std::string connection_string{ cbc::default_connection_string() };
351
+ cbc::fill_cluster_options(options, cluster_options, connection_string);
352
+
353
+ couchbase::query_options query_options{};
354
+ parse_disable_option(query_options.adhoc, "--prepare");
355
+ parse_enable_option(query_options.readonly, "--read-only");
356
+ parse_enable_option(query_options.preserve_expiry, "--preserve-expiry");
357
+ parse_disable_option(query_options.metrics, "--disable-metrics");
358
+ parse_enable_option(query_options.flex_index, "--flex-index");
359
+ parse_integer_option(query_options.max_parallelism, "--maximum-parallelism");
360
+ parse_integer_option(query_options.scan_cap, "--scan-cap");
361
+ parse_integer_option(query_options.pipeline_batch, "--pipeline-batch");
362
+ parse_integer_option(query_options.pipeline_cap, "--pipeline-cap");
363
+ parse_duration_option(query_options.scan_wait, "--scan-wait");
364
+ parse_string_option(query_options.client_context_id, "--client-context-id");
365
+
366
+ if (options.find("--scan-consistency") != options.end() && options.at("--scan-consistency")) {
367
+ if (auto value = options.at("--scan-consistency").asString(); value == "not_bounded") {
368
+ query_options.scan_consistency(couchbase::query_scan_consistency::not_bounded);
369
+ } else if (value == "request_plus") {
370
+ query_options.scan_consistency(couchbase::query_scan_consistency::request_plus);
371
+ } else {
372
+ throw docopt::DocoptArgumentError(fmt::format("unexpected value '{}' for --scan-consistency", value));
373
+ }
374
+ }
375
+
376
+ if (options.find("--profile") != options.end() && options.at("--profile")) {
377
+ if (auto value = options.at("--profile").asString(); value == "off") {
378
+ query_options.profile(couchbase::query_profile::off);
379
+ } else if (value == "phases") {
380
+ query_options.profile(couchbase::query_profile::phases);
381
+ } else if (value == "timings") {
382
+ query_options.profile(couchbase::query_profile::phases);
383
+ } else {
384
+ throw docopt::DocoptArgumentError(fmt::format("unexpected value '{}' for --profile", value));
385
+ }
386
+ }
387
+
388
+ std::optional<scope_with_bucket> scope{};
389
+ if (options.find("--bucket-name") != options.end() && options.at("--bucket-name") &&
390
+ options.find("--scope-name") != options.end() && options.at("--scope-name")) {
391
+ scope = { options.at("--bucket-name").asString(), options.at("--scope-name").asString() };
392
+ }
393
+
394
+ static const std::regex named_param_regex{ R"(^([\w\d_]+)=(.*)$)" };
395
+ if (options.find("--param") != options.end() && options.at("--param")) {
396
+ std::vector<couchbase::codec::binary> positional_params{};
397
+ std::map<std::string, couchbase::codec::binary, std::less<>> named_params{};
398
+
399
+ for (const auto& param : options.at("--param").asStringList()) {
400
+ if (std::smatch match; std::regex_match(param, match, named_param_regex)) {
401
+ named_params[match[1].str()] = std::move(couchbase::core::utils::to_binary(match[2].str()));
402
+ } else {
403
+ positional_params.push_back(couchbase::core::utils::to_binary(param));
404
+ }
405
+ }
406
+ if (!positional_params.empty() && !named_params.empty()) {
407
+ throw docopt::DocoptArgumentError("mixing positional and named parameters is not allowed (parameters must be specified "
408
+ "either as --param=VALUE or --param=NAME=VALUE)");
409
+ }
410
+ if (!positional_params.empty()) {
411
+ query_options.encoded_positional_parameters(std::move(positional_params));
412
+ } else if (!named_params.empty()) {
413
+ query_options.encoded_named_parameters(std::move(named_params));
414
+ }
415
+ }
416
+ if (options.find("--raw") != options.end() && options.at("--raw")) {
417
+ std::map<std::string, couchbase::codec::binary, std::less<>> raw_params{};
418
+ for (const auto& param : options.at("--raw").asStringList()) {
419
+ if (std::smatch match; std::regex_match(param, match, named_param_regex)) {
420
+ raw_params.emplace(match[1].str(), couchbase::core::utils::to_binary(match[2].str()));
421
+ } else {
422
+ throw docopt::DocoptArgumentError("raw parameters should be in NAME=VALUE form, (i.e. --raw=NAME=VALUE)");
423
+ }
424
+ }
425
+ if (!raw_params.empty()) {
426
+ query_options.encoded_raw_options(raw_params);
427
+ }
428
+ }
429
+
430
+ console_output_options output_options{};
431
+ output_options.json_lines = cbc::get_bool_option(options, "--json-lines");
432
+
433
+ auto statements{ options["<statement>"].asStringList() };
434
+ do_work(connection_string, cluster_options, statements, scope, query_options, output_options);
435
+ } catch (const docopt::DocoptArgumentError& e) {
436
+ fmt::print(stderr, "Error: {}\n", e.what());
437
+ } catch (const std::system_error& e) {
438
+ fmt::print(stderr, "Error: {}\n", e.what());
439
+ }
440
+ }
441
+ } // namespace cbc
@@ -0,0 +1,26 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2023-Present Couchbase, 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
+ #include "command.hxx"
19
+
20
+ namespace cbc
21
+ {
22
+ class query : public command
23
+ {
24
+ void execute(const std::vector<std::string>& argv);
25
+ };
26
+ } // namespace cbc