couchbase 3.8.1 → 3.9.0

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 (475) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/CMakeLists.txt +16 -1
  4. data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
  5. data/ext/cache/extconf_include.rb +6 -6
  6. data/ext/cache/mozilla-ca-bundle.crt +214 -155
  7. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  8. data/ext/couchbase/CMakeLists.txt +130 -21
  9. data/ext/couchbase/cmake/APKBUILD.in +25 -4
  10. data/ext/couchbase/cmake/Bundler.cmake +143 -34
  11. data/ext/couchbase/cmake/CPM.cmake +126 -12
  12. data/ext/couchbase/cmake/Cache.cmake +7 -1
  13. data/ext/couchbase/cmake/CompilerOptions.cmake +1 -1
  14. data/ext/couchbase/cmake/CompilerWarnings.cmake +17 -6
  15. data/ext/couchbase/cmake/GrpcProtobuf.cmake +481 -0
  16. data/ext/couchbase/cmake/OpenSSL.cmake +10 -3
  17. data/ext/couchbase/cmake/Packaging.cmake +519 -65
  18. data/ext/couchbase/cmake/Protostellar.cmake +250 -0
  19. data/ext/couchbase/cmake/Sanitizers.cmake +61 -50
  20. data/ext/couchbase/cmake/StaticAnalyzers.cmake +16 -5
  21. data/ext/couchbase/cmake/TestFramework.cmake +283 -0
  22. data/ext/couchbase/cmake/TestFrameworkAddTests.cmake +51 -0
  23. data/ext/couchbase/cmake/Testing.cmake +27 -9
  24. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +141 -8
  25. data/ext/couchbase/cmake/VersionInfo.cmake +50 -0
  26. data/ext/couchbase/cmake/build_config.hxx.in +2 -1
  27. data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +101 -23
  28. data/ext/couchbase/cmake/couchbase_cxx_client_static-config.cmake.in +7 -0
  29. data/ext/couchbase/cmake/couchbase_cxx_client_static.pc.in +2 -0
  30. data/ext/couchbase/cmake/gRPC_Generate.cmake +58 -0
  31. data/ext/couchbase/cmake/protobuf_Generate.cmake +69 -0
  32. data/ext/couchbase/cmake/require-git-checkout.cmake +25 -0
  33. data/ext/couchbase/cmake/tarball_glob.txt +49 -0
  34. data/ext/couchbase/core/agent_group.cxx +0 -8
  35. data/ext/couchbase/core/agent_group.hxx +0 -4
  36. data/ext/couchbase/core/analytics_stream.cxx +314 -0
  37. data/ext/couchbase/core/analytics_stream.hxx +129 -0
  38. data/ext/couchbase/core/analytics_stream_component.cxx +245 -0
  39. data/ext/couchbase/core/analytics_stream_component.hxx +67 -0
  40. data/ext/couchbase/core/app_telemetry_meter.cxx +25 -3
  41. data/ext/couchbase/core/app_telemetry_meter.hxx +77 -0
  42. data/ext/couchbase/core/app_telemetry_reporter.cxx +7 -6
  43. data/ext/couchbase/core/bucket.cxx +381 -87
  44. data/ext/couchbase/core/bucket.hxx +105 -25
  45. data/ext/couchbase/core/bucket_unit_test_api.hxx +57 -0
  46. data/ext/couchbase/core/capella.hxx +91 -0
  47. data/ext/couchbase/core/cluster.cxx +1554 -398
  48. data/ext/couchbase/core/cluster.hxx +39 -8
  49. data/ext/couchbase/core/cluster_agent.cxx +0 -8
  50. data/ext/couchbase/core/cluster_agent.hxx +0 -4
  51. data/ext/couchbase/core/cluster_options.hxx +26 -3
  52. data/ext/couchbase/core/collections_component.cxx +39 -15
  53. data/ext/couchbase/core/config_profiles.cxx +1 -1
  54. data/ext/couchbase/core/crud_component.cxx +2 -2
  55. data/ext/couchbase/core/crud_options.hxx +34 -0
  56. data/ext/couchbase/core/crypto/cbcrypto.cc +18 -13
  57. data/ext/couchbase/core/document_id_redaction.hxx +81 -0
  58. data/ext/couchbase/core/error_context/base_error_context.hxx +7 -6
  59. data/ext/couchbase/core/error_context/key_value.cxx +25 -2
  60. data/ext/couchbase/core/error_context/key_value.hxx +60 -33
  61. data/ext/couchbase/core/error_context/key_value_error_context.hxx +16 -15
  62. data/ext/couchbase/core/error_context/search.hxx +5 -0
  63. data/ext/couchbase/core/error_context/search_json.hxx +3 -0
  64. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +19 -18
  65. data/ext/couchbase/core/error_context/view.hxx +5 -0
  66. data/ext/couchbase/core/free_form_http_request.cxx +237 -4
  67. data/ext/couchbase/core/free_form_http_request.hxx +41 -8
  68. data/ext/couchbase/core/http_component.cxx +300 -284
  69. data/ext/couchbase/core/http_component.hxx +0 -4
  70. data/ext/couchbase/core/impl/analytics.cxx +38 -5
  71. data/ext/couchbase/core/impl/analytics.hxx +34 -0
  72. data/ext/couchbase/core/impl/bootstrap_error.hxx +0 -3
  73. data/ext/couchbase/core/impl/collection.cxx +215 -202
  74. data/ext/couchbase/core/impl/collection_manager.cxx +1 -1
  75. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +45 -18
  76. data/ext/couchbase/core/impl/error.cxx +22 -2
  77. data/ext/couchbase/core/impl/internal_analytics_stream_result.hxx +111 -0
  78. data/ext/couchbase/core/impl/internal_query_stream_result.hxx +110 -0
  79. data/ext/couchbase/core/impl/invoke_with_node_id.hxx +15 -7
  80. data/ext/couchbase/core/impl/key_value_error_category.cxx +6 -0
  81. data/ext/couchbase/core/impl/lookup_in_replica.cxx +10 -10
  82. data/ext/couchbase/core/impl/lookup_in_replica.hxx +4 -4
  83. data/ext/couchbase/core/impl/node_id.cxx +49 -13
  84. data/ext/couchbase/core/impl/observability_recorder.cxx +12 -2
  85. data/ext/couchbase/core/impl/observe_poll.cxx +63 -23
  86. data/ext/couchbase/core/impl/public_analytics_stream_result.cxx +372 -0
  87. data/ext/couchbase/core/impl/public_bucket.cxx +48 -2
  88. data/ext/couchbase/core/impl/public_cluster.cxx +325 -25
  89. data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
  90. data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
  91. data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
  92. data/ext/couchbase/core/impl/query.cxx +76 -7
  93. data/ext/couchbase/core/impl/query.hxx +36 -0
  94. data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
  95. data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
  96. data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
  97. data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
  98. data/ext/couchbase/core/impl/scope.cxx +70 -0
  99. data/ext/couchbase/core/impl/search.cxx +31 -1
  100. data/ext/couchbase/core/impl/transactions.cxx +130 -0
  101. data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
  102. data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
  103. data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
  104. data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
  105. data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +66 -0
  106. data/ext/couchbase/core/io/dns_client.cxx +122 -45
  107. data/ext/couchbase/core/io/dns_codec.hxx +21 -21
  108. data/ext/couchbase/core/io/dns_config.cxx +21 -6
  109. data/ext/couchbase/core/io/http_command.hxx +149 -121
  110. data/ext/couchbase/core/io/http_error.hxx +107 -0
  111. data/ext/couchbase/core/io/http_parser.cxx +4 -0
  112. data/ext/couchbase/core/io/http_session.cxx +606 -154
  113. data/ext/couchbase/core/io/http_session.hxx +147 -30
  114. data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
  115. data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
  116. data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
  117. data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
  118. data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
  119. data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
  120. data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
  121. data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
  122. data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
  123. data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
  124. data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
  125. data/ext/couchbase/core/io/mcbp_session.cxx +316 -317
  126. data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
  127. data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
  128. data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
  129. data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
  130. data/ext/couchbase/core/io/streams.cxx +275 -14
  131. data/ext/couchbase/core/io/streams.hxx +53 -0
  132. data/ext/couchbase/core/logger/logger.cxx +36 -0
  133. data/ext/couchbase/core/logger/logger.hxx +46 -6
  134. data/ext/couchbase/core/logger/redaction.hxx +503 -0
  135. data/ext/couchbase/core/management/eventing_status.hxx +10 -0
  136. data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
  137. data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
  138. data/ext/couchbase/core/mcbp/codec.cxx +27 -18
  139. data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
  140. data/ext/couchbase/core/mcbp/packet.hxx +2 -2
  141. data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
  142. data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
  143. data/ext/couchbase/core/meta/features.hxx +13 -0
  144. data/ext/couchbase/core/meta/version.cxx +6 -3
  145. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
  146. data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
  147. data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
  148. data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
  149. data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
  150. data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
  151. data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
  152. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
  153. data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
  154. data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
  155. data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
  156. data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
  157. data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
  158. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
  159. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
  160. data/ext/couchbase/core/operations/document_query.cxx +108 -221
  161. data/ext/couchbase/core/operations/document_query.hxx +18 -4
  162. data/ext/couchbase/core/operations/document_search.cxx +52 -8
  163. data/ext/couchbase/core/operations/document_search.hxx +3 -0
  164. data/ext/couchbase/core/operations/document_view.cxx +3 -3
  165. data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
  166. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
  167. data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
  168. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
  169. data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
  170. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
  171. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
  172. data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
  173. data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
  174. data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
  175. data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
  176. data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
  177. data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
  178. data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
  179. data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
  180. data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
  181. data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
  182. data/ext/couchbase/core/operations/management/bucket_create.cxx +37 -38
  183. data/ext/couchbase/core/operations/management/bucket_update.cxx +26 -28
  184. data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
  185. data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
  186. data/ext/couchbase/core/operations/management/error_utils.cxx +59 -5
  187. data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
  188. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
  189. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
  190. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
  191. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
  192. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
  193. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
  194. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
  195. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
  196. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
  197. data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
  198. data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
  199. data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
  200. data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
  201. data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
  202. data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
  203. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
  204. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
  205. data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
  206. data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
  207. data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
  208. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
  209. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
  210. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
  211. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
  212. data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
  213. data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
  214. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
  215. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
  216. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
  217. data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
  218. data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
  219. data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
  220. data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
  221. data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
  222. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
  223. data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
  224. data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
  225. data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
  226. data/ext/couchbase/core/operations_fwd.hxx +3 -3
  227. data/ext/couchbase/core/origin.cxx +54 -26
  228. data/ext/couchbase/core/origin.hxx +12 -0
  229. data/ext/couchbase/core/orphan_reporter.cxx +2 -1
  230. data/ext/couchbase/core/platform/random.cc +7 -7
  231. data/ext/couchbase/core/protocol/client_request.cxx +2 -2
  232. data/ext/couchbase/core/protocol/client_request.hxx +38 -21
  233. data/ext/couchbase/core/protocol/client_response.cxx +11 -3
  234. data/ext/couchbase/core/protocol/client_response.hxx +27 -6
  235. data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
  236. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
  237. data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
  238. data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
  239. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
  240. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
  241. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
  242. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
  243. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
  244. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
  245. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
  246. data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
  247. data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
  248. data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
  249. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
  250. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
  251. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
  252. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
  253. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
  254. data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
  255. data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
  256. data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
  257. data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
  258. data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
  259. data/ext/couchbase/core/protocol/datatype.hxx +118 -1
  260. data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
  261. data/ext/couchbase/core/protocol/magic.hxx +4 -0
  262. data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
  263. data/ext/couchbase/core/protocol/server_request.hxx +3 -1
  264. data/ext/couchbase/core/protocol/status.cxx +1 -1
  265. data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
  266. data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
  267. data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
  268. data/ext/couchbase/core/protostellar/component.cxx +2445 -0
  269. data/ext/couchbase/core/protostellar/component.hxx +391 -0
  270. data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
  271. data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
  272. data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
  273. data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
  274. data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
  275. data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
  276. data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
  277. data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
  278. data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
  279. data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
  280. data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
  281. data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
  282. data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
  283. data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
  284. data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
  285. data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
  286. data/ext/couchbase/core/query_stream.cxx +447 -0
  287. data/ext/couchbase/core/query_stream.hxx +141 -0
  288. data/ext/couchbase/core/query_stream_component.cxx +243 -0
  289. data/ext/couchbase/core/query_stream_component.hxx +68 -0
  290. data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
  291. data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
  292. data/ext/couchbase/core/response_handler.hxx +41 -4
  293. data/ext/couchbase/core/row_streamer.cxx +332 -46
  294. data/ext/couchbase/core/row_streamer.hxx +31 -1
  295. data/ext/couchbase/core/row_streamer_options.hxx +55 -0
  296. data/ext/couchbase/core/sasl/client.h +3 -0
  297. data/ext/couchbase/core/search_scoring.hxx +66 -0
  298. data/ext/couchbase/core/stream_error_details.hxx +69 -0
  299. data/ext/couchbase/core/timeout_defaults.hxx +0 -1
  300. data/ext/couchbase/core/topology/capabilities.hxx +6 -0
  301. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  302. data/ext/couchbase/core/topology/configuration.cxx +21 -6
  303. data/ext/couchbase/core/topology/configuration.hxx +29 -8
  304. data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
  305. data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
  306. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
  307. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
  308. data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
  309. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +362 -241
  310. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +24 -3
  311. data/ext/couchbase/core/transactions/error_list.hxx +2 -2
  312. data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
  313. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
  314. data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
  315. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
  316. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
  317. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
  318. data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
  319. data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
  320. data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
  321. data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
  322. data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
  323. data/ext/couchbase/core/transactions/transactions.cxx +3 -55
  324. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +194 -66
  325. data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
  326. data/ext/couchbase/core/transactions/utils.cxx +10 -0
  327. data/ext/couchbase/core/transactions/waitable_op_list.hxx +15 -4
  328. data/ext/couchbase/core/transactions.hxx +9 -9
  329. data/ext/couchbase/core/utils/byteswap.hxx +166 -9
  330. data/ext/couchbase/core/utils/connection_string.cxx +50 -85
  331. data/ext/couchbase/core/utils/connection_string.hxx +15 -0
  332. data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
  333. data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
  334. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
  335. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
  336. data/ext/couchbase/core/utils/movable_function.hxx +301 -52
  337. data/ext/couchbase/core/utils/name_codec.hxx +154 -11
  338. data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
  339. data/ext/couchbase/core/utils/url_codec.cxx +12 -51
  340. data/ext/couchbase/core/websocket_codec.cxx +3 -29
  341. data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
  342. data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
  343. data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
  344. data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
  345. data/ext/couchbase/couchbase/bucket.hxx +57 -0
  346. data/ext/couchbase/couchbase/cluster.hxx +216 -5
  347. data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
  348. data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
  349. data/ext/couchbase/couchbase/collection.hxx +234 -14
  350. data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
  351. data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
  352. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
  353. data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
  354. data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
  355. data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
  356. data/ext/couchbase/couchbase/error.hxx +32 -0
  357. data/ext/couchbase/couchbase/error_codes.hxx +32 -0
  358. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
  359. data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
  360. data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
  361. data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
  362. data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
  363. data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
  364. data/ext/couchbase/couchbase/get_result.hxx +1 -0
  365. data/ext/couchbase/couchbase/increment_options.hxx +1 -1
  366. data/ext/couchbase/couchbase/insert_options.hxx +1 -1
  367. data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
  368. data/ext/couchbase/couchbase/match_query.hxx +1 -1
  369. data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
  370. data/ext/couchbase/couchbase/network_options.hxx +1 -1
  371. data/ext/couchbase/couchbase/node_id.hxx +42 -14
  372. data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
  373. data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
  374. data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
  375. data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
  376. data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
  377. data/ext/couchbase/couchbase/query_options.hxx +23 -12
  378. data/ext/couchbase/couchbase/query_row.hxx +111 -0
  379. data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
  380. data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
  381. data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
  382. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  383. data/ext/couchbase/couchbase/result.hxx +14 -3
  384. data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
  385. data/ext/couchbase/couchbase/scope.hxx +85 -2
  386. data/ext/couchbase/couchbase/search_options.hxx +58 -8
  387. data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
  388. data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
  389. data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
  390. data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
  391. data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
  392. data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
  393. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
  394. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
  395. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
  396. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
  397. data/ext/couchbase/couchbase/transactions.hxx +27 -18
  398. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  399. data/ext/couchbase/couchbase/vector_query.hxx +1 -1
  400. data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
  401. data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
  402. data/ext/extconf.rb +15 -10
  403. data/ext/rcb_analytics.cxx +82 -102
  404. data/ext/rcb_backend.cxx +42 -36
  405. data/ext/rcb_backend.hxx +2 -0
  406. data/ext/rcb_buckets.cxx +47 -59
  407. data/ext/rcb_collections.cxx +42 -52
  408. data/ext/rcb_crud.cxx +345 -224
  409. data/ext/rcb_diagnostics.cxx +117 -27
  410. data/ext/rcb_exceptions.cxx +152 -99
  411. data/ext/rcb_exceptions.hxx +25 -0
  412. data/ext/rcb_extras.cxx +18 -19
  413. data/ext/rcb_hdr_histogram.cxx +19 -4
  414. data/ext/rcb_logger.cxx +202 -27
  415. data/ext/rcb_logger.hxx +12 -0
  416. data/ext/rcb_multi.cxx +40 -40
  417. data/ext/rcb_observability.cxx +7 -5
  418. data/ext/rcb_query.cxx +99 -142
  419. data/ext/rcb_range_scan.cxx +41 -35
  420. data/ext/rcb_search.cxx +98 -99
  421. data/ext/rcb_users.cxx +36 -56
  422. data/ext/rcb_utils.cxx +100 -37
  423. data/ext/rcb_utils.hxx +287 -33
  424. data/ext/rcb_version.cxx +1 -1
  425. data/ext/rcb_views.cxx +55 -51
  426. data/lib/active_support/cache/couchbase_store.rb +77 -12
  427. data/lib/couchbase/bucket.rb +20 -0
  428. data/lib/couchbase/cluster.rb +33 -14
  429. data/lib/couchbase/collection.rb +36 -1
  430. data/lib/couchbase/errors.rb +18 -0
  431. data/lib/couchbase/fork_hooks.rb +16 -7
  432. data/lib/couchbase/get_replica_strategy.rb +89 -0
  433. data/lib/couchbase/logger.rb +1 -1
  434. data/lib/couchbase/management/analytics_index_manager.rb +15 -15
  435. data/lib/couchbase/management/bucket_manager.rb +6 -6
  436. data/lib/couchbase/management/collection_manager.rb +6 -6
  437. data/lib/couchbase/management/query_index_manager.rb +7 -7
  438. data/lib/couchbase/management/search_index_manager.rb +13 -13
  439. data/lib/couchbase/management/user_manager.rb +10 -10
  440. data/lib/couchbase/management/view_index_manager.rb +5 -5
  441. data/lib/couchbase/options.rb +181 -44
  442. data/lib/couchbase/protostellar/bucket.rb +4 -0
  443. data/lib/couchbase/protostellar/cluster.rb +4 -0
  444. data/lib/couchbase/protostellar/collection.rb +4 -0
  445. data/lib/couchbase/protostellar/error_handling.rb +2 -1
  446. data/lib/couchbase/protostellar/request.rb +1 -0
  447. data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
  448. data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
  449. data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
  450. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  451. data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
  452. data/lib/couchbase/search_options.rb +95 -6
  453. data/lib/couchbase/version.rb +1 -1
  454. metadata +92 -33
  455. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
  456. data/ext/couchbase/core/columnar/agent.hxx +0 -71
  457. data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
  458. data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
  459. data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
  460. data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
  461. data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
  462. data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
  463. data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
  464. data/ext/couchbase/core/columnar/error.hxx +0 -51
  465. data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
  466. data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
  467. data/ext/couchbase/core/columnar/management_component.cxx +0 -300
  468. data/ext/couchbase/core/columnar/management_component.hxx +0 -56
  469. data/ext/couchbase/core/columnar/query_component.cxx +0 -523
  470. data/ext/couchbase/core/columnar/query_component.hxx +0 -57
  471. data/ext/couchbase/core/columnar/query_options.hxx +0 -59
  472. data/ext/couchbase/core/columnar/query_result.cxx +0 -130
  473. data/ext/couchbase/core/columnar/query_result.hxx +0 -78
  474. data/ext/couchbase/core/io/config_tracker.cxx +0 -687
  475. data/ext/couchbase/core/io/config_tracker.hxx +0 -123
@@ -16,12 +16,11 @@
16
16
  */
17
17
 
18
18
  #include "document_query.hxx"
19
+ #include "query_response_parsing.hxx"
19
20
 
20
21
  #include "core/cluster_options.hxx"
21
22
  #include "core/logger/logger.hxx"
22
- #include "core/operations/management/error_utils.hxx"
23
- #include "core/utils/contains_string.hxx"
24
- #include "core/utils/duration_parser.hxx"
23
+ #include "core/logger/redaction.hxx"
25
24
  #include "core/utils/json.hxx"
26
25
 
27
26
  #include <couchbase/error_codes.hxx>
@@ -31,40 +30,10 @@
31
30
 
32
31
  namespace couchbase::core::operations
33
32
  {
34
- auto
35
- query_request::encode_to(query_request::encoded_request_type& encoded, http_context& context)
36
- -> std::error_code
33
+ void
34
+ encode_query_options(tao::json::value& body, const query_request& request)
37
35
  {
38
- ctx_.emplace(context);
39
- tao::json::value body{
40
- { "client_context_id", encoded.client_context_id },
41
- };
42
- if (adhoc) {
43
- body["statement"] = statement;
44
- } else {
45
- if (auto entry = ctx_->cache.get(statement)) {
46
- body["prepared"] = entry->name;
47
- if (entry->plan) {
48
- body["encoded_plan"] = entry->plan.value();
49
- }
50
- } else {
51
- body["statement"] = "PREPARE " + statement;
52
- if (context.config.capabilities.supports_enhanced_prepared_statements()) {
53
- body["auto_execute"] = true;
54
- } else {
55
- extract_encoded_plan_ = true;
56
- }
57
- }
58
- }
59
- auto timeout_for_service = encoded.timeout;
60
- if (timeout_for_service > std::chrono::milliseconds(5'000)) {
61
- /* if allocated timeout is large enough, tell query engine, that it is 500ms smaller, to make
62
- * sure we will always get response */
63
- timeout_for_service -= std::chrono::milliseconds(500);
64
- }
65
- body["timeout"] = fmt::format("{}ms", timeout_for_service.count());
66
-
67
- for (const auto& [name, value] : named_parameters) {
36
+ for (const auto& [name, value] : request.named_parameters) {
68
37
  Expects(name.empty() == false);
69
38
  std::string key = name;
70
39
  if (key[0] != '$') {
@@ -72,16 +41,16 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
72
41
  }
73
42
  body[key] = utils::json::parse(value);
74
43
  }
75
- if (!positional_parameters.empty()) {
44
+ if (!request.positional_parameters.empty()) {
76
45
  std::vector<tao::json::value> parameters;
77
- parameters.reserve(positional_parameters.size());
78
- for (const auto& value : positional_parameters) {
46
+ parameters.reserve(request.positional_parameters.size());
47
+ for (const auto& value : request.positional_parameters) {
79
48
  parameters.emplace_back(utils::json::parse(value));
80
49
  }
81
50
  body["args"] = std::move(parameters);
82
51
  }
83
- if (profile.has_value()) {
84
- switch (profile.value()) {
52
+ if (request.profile.has_value()) {
53
+ switch (request.profile.value()) {
85
54
  case couchbase::query_profile::phases:
86
55
  body["profile"] = "phases";
87
56
  break;
@@ -93,44 +62,38 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
93
62
  break;
94
63
  }
95
64
  }
96
- if (use_replica.has_value()) {
97
- if (context.config.capabilities.supports_read_from_replica()) {
98
- if (use_replica.value()) {
99
- body["use_replica"] = "on";
100
- } else {
101
- body["use_replica"] = "off";
102
- }
103
- } else {
104
- return errc::common::feature_not_available;
105
- }
65
+ if (request.use_replica.has_value()) {
66
+ // The capability gate is enforced by the caller (encode_to for buffered, cluster::query_stream
67
+ // for streaming); here we only emit the encoded field.
68
+ body["use_replica"] = request.use_replica.value() ? "on" : "off";
106
69
  }
107
- if (max_parallelism) {
108
- body["max_parallelism"] = std::to_string(max_parallelism.value());
70
+ if (request.max_parallelism) {
71
+ body["max_parallelism"] = std::to_string(request.max_parallelism.value());
109
72
  }
110
- if (pipeline_cap) {
111
- body["pipeline_cap"] = std::to_string(pipeline_cap.value());
73
+ if (request.pipeline_cap) {
74
+ body["pipeline_cap"] = std::to_string(request.pipeline_cap.value());
112
75
  }
113
- if (pipeline_batch) {
114
- body["pipeline_batch"] = std::to_string(pipeline_batch.value());
76
+ if (request.pipeline_batch) {
77
+ body["pipeline_batch"] = std::to_string(request.pipeline_batch.value());
115
78
  }
116
- if (scan_cap) {
117
- body["scan_cap"] = std::to_string(scan_cap.value());
79
+ if (request.scan_cap) {
80
+ body["scan_cap"] = std::to_string(request.scan_cap.value());
118
81
  }
119
- if (!metrics) {
82
+ if (!request.metrics) {
120
83
  body["metrics"] = false;
121
84
  }
122
- if (readonly) {
85
+ if (request.readonly) {
123
86
  body["readonly"] = true;
124
87
  }
125
- if (flex_index) {
88
+ if (request.flex_index) {
126
89
  body["use_fts"] = true;
127
90
  }
128
- if (preserve_expiry) {
91
+ if (request.preserve_expiry) {
129
92
  body["preserve_expiry"] = true;
130
93
  }
131
94
  bool check_scan_wait = false;
132
- if (scan_consistency) {
133
- switch (scan_consistency.value()) {
95
+ if (request.scan_consistency) {
96
+ switch (request.scan_consistency.value()) {
134
97
  case query_scan_consistency::not_bounded:
135
98
  body["scan_consistency"] = "not_bounded";
136
99
  break;
@@ -139,11 +102,11 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
139
102
  body["scan_consistency"] = "request_plus";
140
103
  break;
141
104
  }
142
- } else if (!mutation_state.empty()) {
105
+ } else if (!request.mutation_state.empty()) {
143
106
  check_scan_wait = true;
144
107
  body["scan_consistency"] = "at_plus";
145
108
  tao::json::value scan_vectors = tao::json::empty_object;
146
- for (const auto& token : mutation_state) {
109
+ for (const auto& token : request.mutation_state) {
147
110
  auto* bucket = scan_vectors.find(token.bucket_name());
148
111
  if (bucket == nullptr) {
149
112
  scan_vectors[token.bucket_name()] = tao::json::empty_object;
@@ -156,16 +119,58 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
156
119
  }
157
120
  body["scan_vectors"] = scan_vectors;
158
121
  }
159
- if (check_scan_wait && scan_wait) {
160
- body["scan_wait"] = fmt::format("{}ms", scan_wait.value().count());
122
+ if (check_scan_wait && request.scan_wait) {
123
+ body["scan_wait"] = fmt::format("{}ms", request.scan_wait.value().count());
161
124
  }
162
-
163
- if (query_context) {
164
- body["query_context"] = query_context.value();
125
+ if (request.query_context) {
126
+ body["query_context"] = request.query_context.value();
165
127
  }
166
- for (const auto& [name, value] : raw) {
128
+ for (const auto& [name, value] : request.raw) {
167
129
  body[name] = utils::json::parse(value);
168
130
  }
131
+ }
132
+
133
+ auto
134
+ query_request::encode_to(query_request::encoded_request_type& encoded, http_context& context)
135
+ -> std::error_code
136
+ {
137
+ ctx_.emplace(context);
138
+ tao::json::value body{
139
+ { "client_context_id", encoded.client_context_id },
140
+ };
141
+ if (adhoc) {
142
+ body["statement"] = statement;
143
+ } else {
144
+ if (auto entry = ctx_->cache.get(statement)) {
145
+ body["prepared"] = entry->name;
146
+ if (entry->plan) {
147
+ body["encoded_plan"] = entry->plan.value();
148
+ }
149
+ } else {
150
+ body["statement"] = "PREPARE " + statement;
151
+ if (context.config.capabilities.supports_enhanced_prepared_statements()) {
152
+ body["auto_execute"] = true;
153
+ } else {
154
+ extract_encoded_plan_ = true;
155
+ }
156
+ }
157
+ }
158
+ auto timeout_for_service = encoded.timeout;
159
+ if (timeout_for_service > std::chrono::milliseconds(5'000)) {
160
+ /* if allocated timeout is large enough, tell query engine, that it is 500ms smaller, to make
161
+ * sure we will always get response */
162
+ timeout_for_service -= std::chrono::milliseconds(500);
163
+ }
164
+ body["timeout"] = fmt::format("{}ms", timeout_for_service.count());
165
+
166
+ // use_replica is only honored when the cluster advertises read-from-replica support; reject the
167
+ // request up front otherwise. The field itself is encoded by encode_query_options below.
168
+ if (use_replica.has_value() && !context.config.capabilities.supports_read_from_replica()) {
169
+ return errc::common::feature_not_available;
170
+ }
171
+
172
+ encode_query_options(body, *this);
173
+
169
174
  encoded.type = type;
170
175
  encoded.headers["connection"] = "keep-alive";
171
176
  encoded.headers["content-type"] = "application/json";
@@ -184,18 +189,21 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
184
189
  }
185
190
  body.erase("statement");
186
191
  body.erase("prepared");
192
+ // prep is either the prepared statement name or the boolean false, and only the name is user
193
+ // data. Tagging the boolean hashes a two-value domain to a fixed digest, which hides nothing
194
+ // and destroys the answer to "was this query prepared?" in a redacted log.
187
195
  if (ctx_->options.show_queries) {
188
196
  CB_LOG_INFO("QUERY: client_context_id=\"{}\", prep={}, {}, options={}",
189
197
  encoded.client_context_id,
190
- utils::json::generate(prep),
191
- utils::json::generate(stmt),
192
- utils::json::generate(body));
198
+ logger::user_data_if(prep.is_string(), utils::json::generate(prep)),
199
+ logger::user_data(utils::json::generate(stmt)),
200
+ logger::user_data(utils::json::generate(body)));
193
201
  } else {
194
202
  CB_LOG_DEBUG("QUERY: client_context_id=\"{}\", prep={}, {}, options={}",
195
203
  encoded.client_context_id,
196
- utils::json::generate(prep),
197
- utils::json::generate(stmt),
198
- utils::json::generate(body));
204
+ logger::user_data_if(prep.is_string(), utils::json::generate(prep)),
205
+ logger::user_data(utils::json::generate(stmt)),
206
+ logger::user_data(utils::json::generate(body)));
199
207
  }
200
208
  if (row_callback) {
201
209
  encoded.streaming.emplace(couchbase::core::io::streaming_settings{
@@ -222,6 +230,10 @@ query_request::make_response(error_context::query&& ctx, const encoded_response_
222
230
  response.ctx.ec = errc::common::service_not_available;
223
231
  break;
224
232
 
233
+ case 400:
234
+ response.ctx.ec = errc::common::invalid_argument;
235
+ break;
236
+
225
237
  case 500:
226
238
  default:
227
239
  response.ctx.ec = errc::common::internal_server_failure;
@@ -236,70 +248,18 @@ query_request::make_response(error_context::query&& ctx, const encoded_response_
236
248
  response.ctx.ec = errc::common::parsing_failure;
237
249
  return response;
238
250
  }
239
- if (const auto* i = payload.find("requestID"); i != nullptr) {
240
- response.meta.request_id = i->get_string();
241
- }
251
+ response.meta = parse_query_meta(payload);
242
252
 
243
- if (const auto* i = payload.find("clientContextID"); i != nullptr) {
244
- response.meta.client_context_id = i->get_string();
245
- if (response.ctx.client_context_id != response.meta.client_context_id) {
246
- CB_LOG_WARNING(R"(unexpected clientContextID returned by service: "{}", expected "{}")",
247
- response.meta.client_context_id,
248
- response.ctx.client_context_id);
249
- }
250
- }
251
- if (const auto* s = payload.find("status"); s != nullptr) {
252
- response.meta.status = payload.at("status").get_string();
253
- }
254
- if (const auto* s = payload.find("signature"); s != nullptr) {
255
- response.meta.signature = couchbase::core::utils::json::generate(*s);
253
+ if (response.ctx.client_context_id != response.meta.client_context_id &&
254
+ !response.meta.client_context_id.empty()) {
255
+ CB_LOG_WARNING(R"(unexpected clientContextID returned by service: "{}", expected "{}")",
256
+ response.meta.client_context_id,
257
+ response.ctx.client_context_id);
256
258
  }
259
+
257
260
  if (const auto* c = payload.find("prepared"); c != nullptr) {
258
261
  response.prepared = c->get_string();
259
262
  }
260
- if (const auto* p = payload.find("profile"); p != nullptr) {
261
- response.meta.profile = couchbase::core::utils::json::generate(*p);
262
- }
263
-
264
- if (const auto* m = payload.find("metrics"); m != nullptr) {
265
- query_response::query_metrics meta_metrics{};
266
- meta_metrics.result_count = m->at("resultCount").get_unsigned();
267
- meta_metrics.result_size = m->at("resultSize").get_unsigned();
268
- meta_metrics.elapsed_time = utils::parse_duration(m->at("elapsedTime").get_string());
269
- meta_metrics.execution_time = utils::parse_duration(m->at("executionTime").get_string());
270
- meta_metrics.sort_count = m->template optional<std::uint64_t>("sortCount").value_or(0);
271
- meta_metrics.mutation_count =
272
- m->template optional<std::uint64_t>("mutationCount").value_or(0);
273
- meta_metrics.error_count = m->template optional<std::uint64_t>("errorCount").value_or(0);
274
- meta_metrics.warning_count = m->template optional<std::uint64_t>("warningCount").value_or(0);
275
- response.meta.metrics.emplace(meta_metrics);
276
- }
277
-
278
- if (const auto* e = payload.find("errors"); e != nullptr) {
279
- std::vector<couchbase::core::operations::query_response::query_problem> problems{};
280
- for (const auto& err : e->get_array()) {
281
- couchbase::core::operations::query_response::query_problem problem;
282
- problem.code = err.at("code").get_unsigned();
283
- problem.message = err.at("msg").get_string();
284
- if (const auto* reason = err.find("reason"); reason != nullptr && reason->is_object()) {
285
- problem.reason = reason->optional<std::uint64_t>("code");
286
- problem.retry = reason->optional<bool>("retry");
287
- }
288
- problems.emplace_back(problem);
289
- }
290
- response.meta.errors.emplace(problems);
291
- }
292
-
293
- if (const auto* w = payload.find("warnings"); w != nullptr) {
294
- std::vector<couchbase::core::operations::query_response::query_problem> problems{};
295
- for (const auto& warn : w->get_array()) {
296
- couchbase::core::operations::query_response::query_problem problem;
297
- problem.code = warn.at("code").get_unsigned();
298
- problem.message = warn.at("msg").get_string();
299
- problems.emplace_back(problem);
300
- }
301
- response.meta.warnings.emplace(problems);
302
- }
303
263
 
304
264
  if (const auto* r = payload.find("results"); r != nullptr) {
305
265
  response.rows.reserve(r->get_array().size());
@@ -308,7 +268,8 @@ query_request::make_response(error_context::query&& ctx, const encoded_response_
308
268
  }
309
269
  }
310
270
 
311
- if (response.meta.status == "success") {
271
+ // RFC-58: a 400 is a failure whatever status the body reports.
272
+ if (response.meta.status == "success" && encoded.status_code != 400) {
312
273
  if (response.prepared) {
313
274
  if (ctx_.has_value()) {
314
275
  ctx_->cache.put(statement, response.prepared.value());
@@ -341,22 +302,10 @@ query_request::make_response(error_context::query&& ctx, const encoded_response_
341
302
  if (response.meta.errors && !response.meta.errors->empty()) {
342
303
  response.ctx.first_error_code = response.meta.errors->front().code;
343
304
  response.ctx.first_error_message = response.meta.errors->front().message;
305
+
306
+ // Prepared-statement codes that require cache eviction + retry must be handled
307
+ // before delegating to the pure map_query_error classifier.
344
308
  switch (response.ctx.first_error_code) {
345
- case 1065: /* IKey: "service.io.request.unrecognized_parameter" */
346
- if ((response.ctx.first_error_message.find("Unrecognized parameter in request") !=
347
- std::string::npos) &&
348
- (response.ctx.first_error_message.find("preserve_expiry") != std::string::npos)) {
349
- response.ctx.ec = errc::common::feature_not_available;
350
- } else {
351
- response.ctx.ec = errc::common::invalid_argument;
352
- }
353
- break;
354
- case 1080: /* IKey: "timeout" */
355
- response.ctx.ec = errc::common::unambiguous_timeout;
356
- break;
357
- case 3000: /* IKey: "parse.syntax_error" */
358
- response.ctx.ec = errc::common::parsing_failure;
359
- break;
360
309
  case 4040: /* IKey: "plan.build_prepared.no_such_name" */
361
310
  case 4050: /* IKey: "plan.build_prepared.unrecognized_prepared" */
362
311
  case 4070: /* IKey: "plan.build_prepared.decoding" */
@@ -364,80 +313,18 @@ query_request::make_response(error_context::query&& ctx, const encoded_response_
364
313
  ctx_->cache.erase(statement);
365
314
  }
366
315
  throw couchbase::core::priv::retry_http_request{};
367
- case 4060: /* IKey: "plan.build_prepared.no_such_name" */
368
- case 4080: /* IKey: "plan.build_prepared.name_encoded_plan_mismatch" */
369
- case 4090: /* IKey: "plan.build_prepared.name_not_in_encoded_plan" */
370
- response.ctx.ec = errc::query::prepared_statement_failure;
371
- break;
372
- case 4300: /* IKey: "plan.new_index_already_exists" */
373
- response.ctx.ec = errc::common::index_exists;
374
- break;
375
- case 5000: /* IKey: "Internal Error" */
376
- if (utils::contains_string(response.ctx.first_error_message, "index", true) &&
377
- utils::contains_string(response.ctx.first_error_message, "already exist", true)) {
378
- response.ctx.ec = errc::common::index_exists;
379
- } else if (utils::contains_string(response.ctx.first_error_message,
380
- "Index does not exist") ||
381
- (utils::contains_string(response.ctx.first_error_message, "index", true) &&
382
- utils::contains_string(
383
- response.ctx.first_error_message, "not found", true))) {
384
- response.ctx.ec = errc::common::index_not_found;
385
- } else if (response.ctx.first_error_message.find("Bucket Not Found") !=
386
- std::string::npos) {
387
- response.ctx.ec = errc::common::bucket_not_found;
388
- }
389
- break;
390
- case 12009: /* IKey: "datastore.couchbase.DML_error" */
391
- if (response.ctx.first_error_message.find("CAS mismatch") != std::string::npos) {
392
- response.ctx.ec = errc::common::cas_mismatch;
393
- } else {
394
- switch (response.meta.errors->front().reason.value_or(0)) {
395
- case 12033:
396
- response.ctx.ec = errc::common::cas_mismatch;
397
- break;
398
- case 17014:
399
- response.ctx.ec = errc::key_value::document_not_found;
400
- break;
401
- case 17012:
402
- response.ctx.ec = errc::key_value::document_exists;
403
- break;
404
- default:
405
- response.ctx.ec = errc::query::dml_failure;
406
- break;
407
- }
408
- }
409
- break;
410
-
411
- case 12004: /* IKey: "datastore.couchbase.primary_idx_not_found" */
412
- case 12016: /* IKey: "datastore.couchbase.index_not_found" */
413
- response.ctx.ec = errc::common::index_not_found;
414
- break;
415
- case 13014: /* IKey: "datastore.couchbase.insufficient_credentials" */
416
- response.ctx.ec = errc::common::authentication_failure;
417
- break;
418
316
  default:
419
- if ((response.ctx.first_error_code >= 12000 && response.ctx.first_error_code < 13000) ||
420
- (response.ctx.first_error_code >= 14000 && response.ctx.first_error_code < 15000)) {
421
- response.ctx.ec = errc::query::index_failure;
422
- } else if (response.ctx.first_error_code >= 4000 &&
423
- response.ctx.first_error_code < 5000) {
424
- response.ctx.ec = errc::query::planning_failure;
425
- }
426
317
  break;
427
318
  }
428
- if (!response.ctx.ec) {
429
- auto common_ec = management::extract_common_query_error_code(
430
- response.ctx.first_error_code, response.ctx.first_error_message);
431
- if (common_ec) {
432
- response.ctx.ec = common_ec.value();
433
- }
434
- }
319
+
320
+ response.ctx.ec = map_query_error(response.meta, encoded.status_code);
435
321
  }
436
322
  if (!response.ctx.ec) {
437
323
  CB_LOG_TRACE("Unexpected error returned by query engine: client_context_id=\"{}\", body={}",
438
324
  response.ctx.client_context_id,
439
- encoded.body.data());
440
- response.ctx.ec = errc::common::internal_server_failure;
325
+ logger::user_data(encoded.body.data()));
326
+ response.ctx.ec = encoded.status_code == 400 ? errc::common::invalid_argument
327
+ : errc::common::internal_server_failure;
441
328
  }
442
329
  }
443
330
  }
@@ -29,6 +29,8 @@
29
29
 
30
30
  #include <couchbase/mutation_token.hxx>
31
31
 
32
+ #include <tao/json/forward.hpp>
33
+
32
34
  namespace couchbase::tracing
33
35
  {
34
36
  class request_span;
@@ -36,6 +38,18 @@ class request_span;
36
38
 
37
39
  namespace couchbase::core::operations
38
40
  {
41
+ struct query_request;
42
+
43
+ /**
44
+ * Encodes the shared N1QL request-body options (parameters, profile, replica, consistency, raw,
45
+ * …) common to the buffered and streaming query paths onto @p body. The two paths differ only in
46
+ * how they set the statement/prepared fields, the timeout, and the capability gate; the option
47
+ * block is identical and lives here so both paths stay byte-for-byte consistent. `use_replica` is
48
+ * always encoded when present — the capability gate is the caller's responsibility.
49
+ */
50
+ void
51
+ encode_query_options(tao::json::value& body, const query_request& request);
52
+
39
53
  struct query_response {
40
54
  struct query_metrics {
41
55
  std::chrono::nanoseconds elapsed_time{};
@@ -110,11 +124,11 @@ struct query_request {
110
124
  std::optional<std::function<utils::json::stream_control(std::string)>> row_callback{};
111
125
  std::optional<std::string> send_to_node{};
112
126
 
113
- [[nodiscard]] auto encode_to(encoded_request_type& encoded,
114
- http_context& context) -> std::error_code;
127
+ [[nodiscard]] auto encode_to(encoded_request_type& encoded, http_context& context)
128
+ -> std::error_code;
115
129
 
116
- [[nodiscard]] auto make_response(error_context::query&& ctx,
117
- const encoded_response_type& encoded) -> query_response;
130
+ [[nodiscard]] auto make_response(error_context::query&& ctx, const encoded_response_type& encoded)
131
+ -> query_response;
118
132
 
119
133
  std::optional<http_context> ctx_{};
120
134
  bool extract_encoded_plan_{ false };
@@ -19,7 +19,9 @@
19
19
 
20
20
  #include "core/cluster_options.hxx"
21
21
  #include "core/logger/logger.hxx"
22
+ #include "core/logger/redaction.hxx"
22
23
  #include "core/utils/json.hxx"
24
+ #include "core/utils/url_codec.hxx"
23
25
 
24
26
  #include <couchbase/error_codes.hxx>
25
27
 
@@ -31,6 +33,10 @@ auto
31
33
  search_request::encode_to(search_request::encoded_request_type& encoded,
32
34
  http_context& context) -> std::error_code
33
35
  {
36
+ if (disable_scoring && !std::holds_alternative<std::monostate>(scoring)) {
37
+ return errc::common::invalid_argument;
38
+ }
39
+
34
40
  auto body = tao::json::value{
35
41
  { "query", utils::json::parse(query) },
36
42
  { "ctl", { { "timeout", encoded.timeout.count() } } },
@@ -66,6 +72,39 @@ search_request::encode_to(search_request::encoded_request_type& encoded,
66
72
  if (disable_scoring) {
67
73
  body["score"] = "none";
68
74
  }
75
+ if (!std::holds_alternative<std::monostate>(scoring)) {
76
+ std::optional<std::uint32_t> score_rank_constant{};
77
+ std::optional<std::uint32_t> score_window_size{};
78
+ std::visit(
79
+ [&body, &score_rank_constant, &score_window_size](const auto& value) {
80
+ using T = std::decay_t<decltype(value)>;
81
+ if constexpr (std::is_same_v<T, couchbase::core::search_scoring_none>) {
82
+ body["score"] = "none";
83
+ } else if constexpr (std::is_same_v<
84
+ T,
85
+ couchbase::core::search_scoring_reciprocal_rank_fusion>) {
86
+ body["score"] = "rrf";
87
+ score_rank_constant = value.rank_constant;
88
+ score_window_size = value.window_size;
89
+ } else if constexpr (std::is_same_v<
90
+ T,
91
+ couchbase::core::search_scoring_relative_score_fusion>) {
92
+ body["score"] = "rsf";
93
+ score_window_size = value.window_size;
94
+ }
95
+ },
96
+ scoring);
97
+ tao::json::value params = tao::json::empty_object;
98
+ if (score_rank_constant.has_value()) {
99
+ params["score_rank_constant"] = score_rank_constant.value();
100
+ }
101
+ if (score_window_size.has_value()) {
102
+ params["score_window_size"] = score_window_size.value();
103
+ }
104
+ if (!params.get_object().empty()) {
105
+ body["params"] = params;
106
+ }
107
+ }
69
108
  if (include_locations) {
70
109
  body["includeLocations"] = true;
71
110
  }
@@ -126,11 +165,12 @@ search_request::encode_to(search_request::encoded_request_type& encoded,
126
165
 
127
166
  if (bucket_name.has_value() && scope_name.has_value()) {
128
167
  encoded.path = fmt::format("/api/bucket/{}/scope/{}/index/{}/query",
129
- bucket_name.value(),
130
- scope_name.value(),
131
- index_name);
168
+ utils::string_codec::v2::path_escape(bucket_name.value()),
169
+ utils::string_codec::v2::path_escape(scope_name.value()),
170
+ utils::string_codec::v2::path_escape(index_name));
132
171
  } else {
133
- encoded.path = fmt::format("/api/index/{}/query", index_name);
172
+ encoded.path =
173
+ fmt::format("/api/index/{}/query", utils::string_codec::v2::path_escape(index_name));
134
174
  }
135
175
 
136
176
  encoded.type = type;
@@ -139,9 +179,9 @@ search_request::encode_to(search_request::encoded_request_type& encoded,
139
179
  body_str = utils::json::generate(body);
140
180
  encoded.body = body_str;
141
181
  if (context.options.show_queries || (log_request.has_value() && log_request.value())) {
142
- CB_LOG_INFO("SEARCH: {}", utils::json::generate(body));
182
+ CB_LOG_INFO("SEARCH: {}", logger::user_data(utils::json::generate(body)));
143
183
  } else {
144
- CB_LOG_DEBUG("SEARCH: {}", utils::json::generate(body));
184
+ CB_LOG_DEBUG("SEARCH: {}", logger::user_data(utils::json::generate(body)));
145
185
  }
146
186
  if (row_callback) {
147
187
  encoded.streaming.emplace(couchbase::core::io::streaming_settings{
@@ -172,7 +212,7 @@ search_request::make_response(error_context::search&& ctx,
172
212
  return response;
173
213
  }
174
214
  if (log_response.has_value() && log_response.value()) {
175
- CB_LOG_INFO("SEARCH RESPONSE: {}", utils::json::generate(payload));
215
+ CB_LOG_INFO("SEARCH RESPONSE: {}", logger::user_data(utils::json::generate(payload)));
176
216
  }
177
217
  response.meta.metrics.took = std::chrono::nanoseconds(payload.at("took").get_unsigned());
178
218
  response.meta.metrics.max_score = payload.at("max_score").as<double>();
@@ -346,7 +386,11 @@ search_request::make_response(error_context::search&& ctx,
346
386
  response.ctx.ec = errc::common::quota_limited;
347
387
  return response;
348
388
  }
349
- } else if (encoded.status_code == 429) {
389
+ // RFC-58: a 400 not mapped above is invalid_argument.
390
+ response.ctx.ec = errc::common::invalid_argument;
391
+ return response;
392
+ }
393
+ if (encoded.status_code == 429) {
350
394
  tao::json::value payload{};
351
395
  try {
352
396
  payload = utils::json::parse(encoded.body.data());
@@ -26,6 +26,7 @@
26
26
  #include "core/public_fwd.hxx"
27
27
  #include "core/search_highlight_style.hxx"
28
28
  #include "core/search_scan_consistency.hxx"
29
+ #include "core/search_scoring.hxx"
29
30
  #include "core/timeout_defaults.hxx"
30
31
  #include "core/vector_query_combination.hxx"
31
32
 
@@ -164,6 +165,8 @@ struct search_request {
164
165
  std::optional<bool> log_request{ false };
165
166
  std::optional<bool> log_response{ false };
166
167
 
168
+ couchbase::core::search_scoring_mode scoring{};
169
+
167
170
  [[nodiscard]] auto encode_to(encoded_request_type& encoded,
168
171
  http_context& context) -> std::error_code;
169
172
 
@@ -127,10 +127,10 @@ document_view_request::encode_to(document_view_request::encoded_request_type& en
127
127
  encoded.method = "POST";
128
128
  encoded.headers["content-type"] = "application/json";
129
129
  encoded.path = fmt::format("/{}/_design/{}{}/_view/{}?{}",
130
- bucket_name,
130
+ utils::string_codec::v2::path_escape(bucket_name),
131
131
  ns == design_document_namespace::development ? "dev_" : "",
132
- document_name,
133
- view_name,
132
+ utils::string_codec::v2::path_escape(document_name),
133
+ utils::string_codec::v2::path_escape(view_name),
134
134
  utils::join_strings(query_string, "&"));
135
135
  encoded.body = utils::json::generate(body);
136
136
  if (row_callback) {