1 /* 2 * Copyright 2017 Couchbase, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 **/ 16 17 #ifndef LCB_N1QL_API_H 18 #define LCB_N1QL_API_H 19 #include <libcouchbase/couchbase.h> 20 #include <libcouchbase/api3.h> 21 22 #ifdef __cplusplus 23 extern "C" { 24 #endif 25 26 /** 27 * @ingroup lcb-public-api 28 * @defgroup lcb-n1ql-api N1QL/Analytics 29 * @brief Execute N1QL/Analytics queries. 30 * 31 * Query language based on SQL, but designed for structured and flexible JSON 32 * documents. Querying can solve typical programming tasks such as finding a 33 * user profile by email address, performing aggregations etc. 34 * 35 * @code{.c} 36 * const char *query = "{\"statement\":\"SELECT * FROM breweries LIMIT 10\"}"; 37 * lcb_CMDN1QL cmd = {0}; 38 * int idx = 0; 39 * // NOTE: with this flag, the request will be issued to Analytics service 40 * cmd.cmdflags = LCB_CMDN1QL_F_ANALYTICSQUERY; 41 * cmd.callback = row_callback; 42 * cmd.query = query; 43 * cmd.nquery = strlen(query); 44 * lcb_n1ql_query(instance, &idx, &cmd); 45 * lcb_wait(instance); 46 * @endcode 47 * 48 * Where row_callback might be implemented like this: 49 * 50 * @code{.c} 51 * static void row_callback(lcb_t instance, int type, const lcb_RESPN1QL *resp) 52 * { 53 * int *idx = (int *)resp->cookie; 54 * if (resp->rc != LCB_SUCCESS) { 55 * printf("failed to execute query: %s\n", lcb_strerror_short(resp->rc)); 56 * exit(EXIT_FAILURE); 57 * } 58 * if (resp->rflags & LCB_RESP_F_FINAL) { 59 * printf("META: "); 60 * } else { 61 * printf("ROW #%d: ", (*idx)++); 62 * } 63 * printf("%.*s\n", (int)resp->nrow, (char *)resp->row); 64 * } 65 * @endcode 66 * 67 * @see more details on @ref lcb_n1ql_query and @ref lcb_CMDN1QL. 68 * 69 * Also there is a query builder available for N1QL queries: @ref lcb_n1p_new/@ref lcb_n1p_mkcmd. 70 */ 71 72 /** 73 * @addtogroup lcb-n1ql-api 74 * @{ 75 */ 76 typedef struct lcb_RESPN1QL lcb_RESPN1QL; 77 typedef struct lcb_CMDN1QL lcb_CMDN1QL; 78 /** 79 * Pointer for request instance 80 */ 81 typedef struct lcb_N1QLREQ* lcb_N1QLHANDLE; 82 83 /** 84 * Callback to be invoked for each row 85 * @param The instance 86 * @param Callback type. This is set to @ref LCB_CALLBACK_N1QL 87 * @param The response. 88 */ 89 typedef void (*lcb_N1QLCALLBACK)(lcb_t, int, const lcb_RESPN1QL*); 90 91 /** 92 * @name N1QL Parameters 93 * 94 * The following APIs simply provide wrappers for creating the proper HTTP 95 * form parameters for N1QL requests. The general flow is to create a 96 * parameters (@ref lcb_N1QLPARAMS) object, set various options and properties 97 * on it, and populate an @ref lcb_CMDN1QL object using the lcb_n1p_mkcmd() 98 * function. 99 * 100 * @{ 101 */ 102 103 /** 104 * Opaque object representing N1QL parameters. 105 * This object is created via lcb_n1p_new(), may be cleared 106 * (for use with another query) via lcb_n1p_reset(), and may be freed via 107 * lcb_n1p_free(). 108 */ 109 typedef struct lcb_N1QLPARAMS_st lcb_N1QLPARAMS; 110 111 /** 112 * Create a new N1QL Parameters object. The returned object is an opaque 113 * pointer which may be used to set various properties on a N1QL query. This 114 * may then be used to populate relevant fields of an @ref lcb_CMDN1QL 115 * structure. 116 */ 117 LIBCOUCHBASE_API 118 lcb_N1QLPARAMS * 119 lcb_n1p_new(void); 120 121 /** 122 * Reset the parameters structure so that it may be reused for a subsequent 123 * query. Internally this resets the buffer positions to 0, but does not free 124 * them, making this function optimal for issusing subsequent queries. 125 * @param params the object to reset 126 */ 127 LIBCOUCHBASE_API 128 void 129 lcb_n1p_reset(lcb_N1QLPARAMS *params); 130 131 /** 132 * Free the parameters structure. This should be done when it is no longer 133 * needed 134 * @param params the object to reset 135 */ 136 LIBCOUCHBASE_API 137 void 138 lcb_n1p_free(lcb_N1QLPARAMS *params); 139 140 /** Query is a statement string */ 141 #define LCB_N1P_QUERY_STATEMENT 1 142 143 /** @internal */ 144 #define LCB_N1P_QUERY_PREPARED 2 145 146 /** 147 * Sets the actual statement to be executed 148 * @param params the params object 149 * @param qstr the query string (either N1QL statement or prepared JSON) 150 * @param nqstr the length of the string. Set to -1 if NUL-terminated 151 * @param type the type of statement. Should be ::LCB_N1P_QUERY_STATEMENT, 152 * currently. 153 */ 154 LIBCOUCHBASE_API 155 lcb_error_t 156 lcb_n1p_setquery(lcb_N1QLPARAMS *params, const char *qstr, size_t nqstr, int type); 157 158 /** Shortcut to set NUL-terminated string as statement via @ref lcb_n1p_setquery */ 159 #define lcb_n1p_setstmtz(params, qstr) \ 160 lcb_n1p_setquery(params, qstr, -1, LCB_N1P_QUERY_STATEMENT) 161 162 /** 163 * Sets a named argument for the query. 164 * @param params the object 165 * @param name The argument name (e.g. `$age`) 166 * @param n_name 167 * @param value The argument value (e.g. `42`) 168 * @param n_value 169 */ 170 LIBCOUCHBASE_API 171 lcb_error_t 172 lcb_n1p_namedparam(lcb_N1QLPARAMS *params, const char *name, size_t n_name, 173 const char *value, size_t n_value); 174 175 /** Shortcut to set NUL-terminated string as named param via @ref lcb_n1p_namedparam */ 176 #define lcb_n1p_namedparamz(params, name, value) \ 177 lcb_n1p_namedparam(params, name, -1, value, -1) 178 179 /** 180 * Adds a _positional_ argument for the query 181 * @param params the params object 182 * @param value the argument 183 * @param n_value the length of the argument. 184 */ 185 LIBCOUCHBASE_API 186 lcb_error_t 187 lcb_n1p_posparam(lcb_N1QLPARAMS *params, const char *value, size_t n_value); 188 189 190 /** 191 * Marks query as read-only. 192 * 193 * If the user knows the request is only ever a select, for security 194 * reasons it can make sense to tell the server this thing is readonly 195 * and it will prevent mutations from happening. 196 * 197 * If readonly is set, then the following statements are not allowed: 198 * * CREATE INDEX 199 * * DROP INDEX 200 * * INSERT 201 * * MERGE 202 * * UPDATE 203 * * UPSERT 204 * * DELETE 205 * 206 * @param params the params object 207 * @param readonly if non-zero, the query will be read-only 208 */ 209 LIBCOUCHBASE_API 210 lcb_error_t 211 lcb_n1p_readonly(lcb_N1QLPARAMS *params, int readonly); 212 213 /** 214 * Sets maximum buffered channel size between the indexer client 215 * and the query service for index scans. 216 * 217 * This parameter controls when to use scan backfill. Use 0 or 218 * a negative number to disable. 219 * 220 * @param params the params object 221 * @param scancap channel size 222 */ 223 LIBCOUCHBASE_API 224 lcb_error_t 225 lcb_n1p_scancap(lcb_N1QLPARAMS *params, int scancap); 226 227 /** 228 * Sets maximum number of items each execution operator can buffer 229 * between various operators. 230 * 231 * @param params the params object 232 * @param pipelinecap number of items 233 */ 234 LIBCOUCHBASE_API 235 lcb_error_t 236 lcb_n1p_pipelinecap(lcb_N1QLPARAMS *params, int pipelinecap); 237 238 /** 239 * Sets the number of items execution operators can batch for 240 * fetch from the KV. 241 * 242 * @param params the params object 243 * @param pipelinebatch number of items 244 */ 245 LIBCOUCHBASE_API 246 lcb_error_t 247 lcb_n1p_pipelinebatch(lcb_N1QLPARAMS *params, int pipelinebatch); 248 249 /** 250 * Set a query option 251 * @param params the params object 252 * @param name the name of the option 253 * @param n_name 254 * @param value the value of the option 255 * @param n_value 256 */ 257 LIBCOUCHBASE_API 258 lcb_error_t 259 lcb_n1p_setopt(lcb_N1QLPARAMS *params, const char *name, size_t n_name, 260 const char *value, size_t n_value); 261 262 /** 263 * Convenience function to set a string parameter with a string value 264 * @param params the parameter object 265 * @param key the NUL-terminated option name 266 * @param value the NUL-terminated option value 267 */ 268 #define lcb_n1p_setoptz(params, key, value) \ 269 lcb_n1p_setopt(params, key, -1, value, -1) 270 271 272 /** No consistency constraints */ 273 #define LCB_N1P_CONSISTENCY_NONE 0 274 275 /** 276 * This is implicitly set by the lcb_n1p_synctok() family of functions. This 277 * will ensure that mutations up to the vector indicated by the mutation token 278 * passed to lcb_n1p_synctok() are used. 279 */ 280 #define LCB_N1P_CONSISTENCY_RYOW 1 281 282 /** Refresh the snapshot for each request */ 283 #define LCB_N1P_CONSISTENCY_REQUEST 2 284 285 /** Refresh the snapshot for each statement */ 286 #define LCB_N1P_CONSISTENCY_STATEMENT 3 287 288 /** 289 * Sets the consistency mode for the request. 290 * By default results are read from a potentially stale snapshot of the data. 291 * This may be good for most cases; however at times you want the absolutely 292 * most recent data. 293 * @param params the parameters object 294 * @param mode one of the `LCB_N1P_CONSISTENT_*` constants. 295 */ 296 LIBCOUCHBASE_API 297 lcb_error_t 298 lcb_n1p_setconsistency(lcb_N1QLPARAMS *params, int mode); 299 300 /** 301 * Indicate that the query should synchronize its internal snapshot to reflect 302 * the changes indicated by the given mutation token (`ss`). 303 * @param params the parameters object 304 * @param keyspace the keyspace (or bucket name) which this mutation token 305 * pertains to 306 * @param st the mutation token 307 */ 308 LIBCOUCHBASE_API 309 lcb_error_t 310 lcb_n1p_setconsistent_token(lcb_N1QLPARAMS *params, 311 const char *keyspace, const lcb_MUTATION_TOKEN *st); 312 313 /** 314 * Indicate that the query should synchronize its internal snapshot to reflect 315 * any past changes made by the given instance `instance`. 316 * 317 * This iterates over all the vbuckets for the given instance and inserts 318 * the relevant mutation token, using @ref lcb_get_mutation_token 319 */ 320 LIBCOUCHBASE_API 321 lcb_error_t 322 lcb_n1p_setconsistent_handle(lcb_N1QLPARAMS *params, lcb_t instance); 323 324 /** 325 * Encodes the request and returns it as a string. The string is valid 326 * until the next call to the params function. 327 * @param params the parameter object 328 * @param[out] rc an error code if there was an issue in encoding 329 * @return the NUL-terminated query string. 330 * 331 * @note Calling this function regenerates the query string internally, 332 * and is implicitly called by lcb_n1p_mkcmd(). 333 */ 334 LIBCOUCHBASE_API 335 const char * 336 lcb_n1p_encode(lcb_N1QLPARAMS *params, lcb_error_t *rc); 337 338 /** 339 * Populates the given low-level lcb_CMDN1QL structure with the relevant fields 340 * from the params structure. If this function returns successfuly, you must 341 * ensure that the params object is not modified until the command is 342 * submitted. 343 * 344 * @note 345 * This may also set some lcb_CMDN1QL::cmdflags fields. If setting your own 346 * flags, ensure that those flags do not replace the existing ones set by 347 * this function. 348 */ 349 LIBCOUCHBASE_API 350 lcb_error_t 351 lcb_n1p_mkcmd(lcb_N1QLPARAMS *params, lcb_CMDN1QL *cmd); 352 353 /**@}*/ 354 355 /** 356 * @name Low-level N1QL interface 357 * @{ 358 */ 359 360 /** 361 * Prepare and cache the query if required. This may be used on frequently 362 * issued queries, so they perform better. 363 */ 364 #define LCB_CMDN1QL_F_PREPCACHE (1 << 16) 365 366 /** The lcb_CMDN1QL::query member is an internal JSON structure. @internal */ 367 #define LCB_CMDN1QL_F_JSONQUERY (1 << 17) 368 369 /** 370 * This is an Analytics query. 371 * 372 * @committed 373 */ 374 #define LCB_CMDN1QL_F_ANALYTICSQUERY (1 << 18) 375 /* @private an alias for compatibility */ 376 #define LCB_CMDN1QL_F_CBASQUERY LCB_CMDN1QL_F_ANALYTICSQUERY 377 378 /** 379 * Command structure for N1QL queries. Typically an application will use the 380 * lcb_N1QLPARAMS structure to populate the #query and #content_type fields. 381 * 382 * The #callback field must be specified, and indicates the function the 383 * library should call when more response data has arrived. 384 */ 385 struct lcb_CMDN1QL { 386 lcb_U32 cmdflags; 387 /**Query to be placed in the POST request. The library will not perform 388 * any conversions or validation on this string, so it is up to the user 389 * (or wrapping library) to ensure that the string is well formed. 390 * 391 * If using the @ref lcb_N1QLPARAMS structure, the lcb_n1p_mkcmd() function 392 * will properly populate this field. 393 * 394 * In general the string should either be JSON (in which case, the 395 * #content_type field should be `application/json`) or url-encoded 396 * (in which case the #content_type field should be 397 * `application/x-www-form-urlencoded`) 398 */ 399 const char *query; 400 401 /** Length of the query data */ 402 size_t nquery; 403 404 /** 405 * Ignored since version 2.5.3. 406 * Starting from version 2.7.3, is used for experimental CBAS support 407 */ 408 const char *host; 409 410 /** Ignored since version 2.5.3 */ 411 const char *content_type; 412 413 /** Callback to be invoked for each row */ 414 lcb_N1QLCALLBACK callback; 415 416 /**Request handle. Will be set to the handle which may be passed to 417 * lcb_n1ql_cancel() */ 418 lcb_N1QLHANDLE *handle; 419 }; 420 421 /** 422 * Response for a N1QL query. This is delivered in the @ref lcb_N1QLCALLBACK 423 * callback function for each result row received. The callback is also called 424 * one last time when all 425 */ 426 struct lcb_RESPN1QL { 427 #ifndef __LCB_DOXYGEN__ 428 LCB_RESP_BASE 429 #else 430 lcb_U16 rflags; /**< Flags for response structure */ 431 #endif 432 433 /**Current result row. If #rflags has the ::LCB_RESP_F_FINAL bit set, then 434 * this field does not contain the actual row, but the remainder of the 435 * data not included with the resultset; e.g. the JSON surrounding 436 * the "results" field with any errors or metadata for the response. 437 */ 438 const char *row; 439 /** Length of the row */ 440 size_t nrow; 441 /** Raw HTTP response, if applicable */ 442 const lcb_RESPHTTP *htresp; 443 }; 444 445 /** 446 * @volatile 447 * 448 * Execute a N1QL query. 449 * 450 * This function will send the query to a query server in the cluster 451 * and will invoke the callback (lcb_CMDN1QL::callback) for each result returned. 452 * By default it will run query as N1QL flavour, for Analytics set 453 * @ref LCB_CMDN1QL_F_ANALYTICSQUERY flag in cmdflags of @ref lcb_CMDN1QL argument. 454 * 455 * @param instance The instance 456 * @param cookie Pointer to application data 457 * @param cmd the command 458 * @return Scheduling success or failure. 459 */ 460 LIBCOUCHBASE_API 461 lcb_error_t 462 lcb_n1ql_query(lcb_t instance, const void *cookie, const lcb_CMDN1QL *cmd); 463 464 465 /** 466 * Cancels an in-progress request. This will ensure that further callbacks 467 * for the given request are not delivered. 468 * 469 * @param instance the instance 470 * @param handle the handle for the request. This is obtained during the 471 * request as an 'out' parameter (see lcb_CMDN1QL::handle) 472 * 473 * To obtain the `handle` parameter, do something like this: 474 * 475 * @code{.c} 476 * lcb_N1QLHANDLE handle; 477 * lcb_CMDN1QL cmd; 478 * // (Initialize command...) 479 * cmd.handle = &handle; 480 * lcb_n1ql_query(instance, cookie, &cmd); 481 * @endcode. 482 * 483 * If the lcb_n1ql_query() function returns `LCB_SUCCESS` then the `handle` 484 * above is populated with the opaque handle. You can then use this handle 485 * to cancel the query at a later point, such as within the callback. 486 * 487 * @code{.c} 488 * lcb_n1ql_cancel(instance, handle); 489 * @endcode 490 */ 491 LIBCOUCHBASE_API 492 void 493 lcb_n1ql_cancel(lcb_t instance, lcb_N1QLHANDLE handle); 494 495 /**@}*/ 496 497 /**@}*/ 498 499 /** 500 * @ingroup lcb-public-api 501 * @addtogroup lcb-tracing-api 502 * @{ 503 */ 504 #ifdef LCB_TRACING 505 506 /** 507 * Associate parent tracing span with the N1QL request. 508 * 509 * @param instance the instance 510 * @param handle N1QL request handle 511 * @param span parent span 512 * 513 * @par Attach parent tracing span to request object. 514 * @code{.c} 515 * lcb_CMDN1QL cmd = {}; 516 * // initialize N1QL command... 517 * 518 * lcb_N1QLHANDLE handle = NULL; 519 * cmd->handle = &handle; 520 * 521 * lcb_error_t err = lcb_fts_query(instance, cookie, cmd); 522 * if (err == LCB_SUCCESS) { 523 * lcb_n1ql_set_parent_span(instance, handle, span); 524 * } 525 * @endcode 526 * 527 * @committed 528 */ 529 LIBCOUCHBASE_API 530 void lcb_n1ql_set_parent_span(lcb_t instance, lcb_N1QLHANDLE handle, lcbtrace_SPAN *span); 531 532 #endif 533 /** 534 * @} (Group: Tracing) 535 */ 536 #ifdef __cplusplus 537 } 538 #endif 539 #endif 540