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