All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
aerospike_query.h
Go to the documentation of this file.
1 /*
2  * Copyright 2008-2017 Aerospike, Inc.
3  *
4  * Portions may be licensed to Aerospike, Inc. under one or more contributor
5  * license agreements.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8  * use this file except in compliance with the License. You may obtain a copy of
9  * the License at http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14  * License for the specific language governing permissions and limitations under
15  * the License.
16  */
17 #pragma once
18 
19 /**
20  * @defgroup query_operations Query Operations
21  * @ingroup client_operations
22  *
23  * The Aerospike Query Operations provide the ability to query data in the
24  * Aerospike database. The queries can only be performed on secondary indexes,
25  * which have been created in the database. To scan all the records in the
26  * database, then you must use the @ref scan_operations.
27  *
28  * ## Usage
29  *
30  * Before you can execute a query, you first need to build a query using
31  * as_query. See as_query for details on building queries.
32  *
33  * Once you have a query defined, then you can execute the query :
34  *
35  * - aerospike_query_foreach() - Executes a query and invokes a callback
36  * function for each result returned.
37  *
38  * When aerospike_query_foreach() is executed, it will process the results
39  * and create records on the stack. Because the records are on the stack,
40  * they will only be available within the context of the callback function.
41  *
42  *
43  * ## Walk-through
44  *
45  * First, we define a query using as_query. The query will be for the "test"
46  * namespace and "demo" set. We will add a where predicate on "bin2", on which
47  * we have already created a secondary index.
48  *
49  * ~~~~~~~~~~{.c}
50  * as_query query;
51  * as_query_init(&query, "test", "demo");
52  *
53  * as_query_where_init(&query, 1);
54  * as_query_where(&query, "bin2", as_integer_equals(100));
55  * ~~~~~~~~~~
56  *
57  * Now that we have a query defined, we want to execute it using
58  * aerospike_query_foreach().
59  *
60  * ~~~~~~~~~~{.c}
61  * if ( aerospike_query_foreach(&as, &err, NULL, &query, callback, NULL) != AEROSPIKE_OK ) {
62  * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line);
63  * }
64  * ~~~~~~~~~~
65  *
66  * The callback provided to the function above is implemented as:
67  *
68  * ~~~~~~~~~~{.c}
69  * bool callback(const as_val * val, void * udata) {
70  * as_record * rec = as_record_fromval(val);
71  * if ( !rec ) return false;
72  * fprintf("record contains %d bins", as_record_numbins(rec));
73  * return true;
74  * }
75  * ~~~~~~~~~~
76  *
77  * An as_query is simply a query definition, so it does not contain any state,
78  * allowing it to be reused for multiple query operations.
79  *
80  * When you are finished with the query, you should destroy the resources
81  * allocated to it:
82  *
83  * ~~~~~~~~~~{.c}
84  * as_query_destroy(&query);
85  * ~~~~~~~~~~
86  *
87  */
88 
89 #include <aerospike/aerospike.h>
90 #include <aerospike/as_error.h>
91 #include <aerospike/as_event.h>
92 #include <aerospike/as_job.h>
93 #include <aerospike/as_policy.h>
94 #include <aerospike/as_query.h>
95 #include <aerospike/as_record.h>
96 #include <aerospike/as_status.h>
97 #include <aerospike/as_stream.h>
98 
99 #ifdef __cplusplus
100 extern "C" {
101 #endif
102 
103 /******************************************************************************
104  * TYPES
105  *****************************************************************************/
106 
107 /**
108  * This callback will be called for each value or record returned from a query.
109  * Multiple threads will likely be calling this callback in parallel. Therefore,
110  * your callback implementation should be thread safe.
111  *
112  * The aerospike_query_foreach() function accepts this callback.
113  *
114  * ~~~~~~~~~~{.c}
115  * bool my_callback(as_val * val, void * udata) {
116  * return true;
117  * }
118  * ~~~~~~~~~~
119  *
120  * @param val The value received from the query.
121  * @param udata User-data provided to the calling function.
122  *
123  * @return `true` to continue to the next value. Otherwise, iteration will end.
124  *
125  * @ingroup query_operations
126  */
127 typedef bool (*aerospike_query_foreach_callback)(const as_val* val, void* udata);
128 
129 /**
130  * Asynchronous query user callback. This function is called for each record returned.
131  * This function is also called once when the query completes or an error has occurred.
132  *
133  * @param err This error structure is only populated when the command fails. Null on success.
134  * @param record Returned record. Use as_val_reserve() on record to prevent calling function from destroying.
135  * The record will be null on final query completion or query error.
136  * @param udata User data that is forwarded from asynchronous command function.
137  * @param event_loop Event loop that this command was executed on. Use this event loop when running
138  * nested asynchronous commands when single threaded behavior is desired for the
139  * group of commands.
140  *
141  * @return `true` to continue to the next value. Otherwise, the query will end.
142  *
143  * @ingroup query_operations
144  */
145 typedef bool (*as_async_query_record_listener)(as_error* err, as_record* record, void* udata, as_event_loop* event_loop);
146 
147 /******************************************************************************
148  * FUNCTIONS
149  *****************************************************************************/
150 
151 /**
152  * Execute a query and call the callback function for each result item.
153  * Multiple threads will likely be calling the callback in parallel. Therefore,
154  * your callback implementation should be thread safe.
155  *
156  * ~~~~~~~~~~{.c}
157  * as_query query;
158  * as_query_init(&query, "test", "demo");
159  * as_query_select(&query, "bin1");
160  * as_query_where(&query, "bin2", as_integer_equals(100));
161  *
162  * if ( aerospike_query_foreach(&as, &err, NULL, &query, callback, NULL) != AEROSPIKE_OK ) {
163  * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line);
164  * }
165  *
166  * as_query_destroy(&query);
167  * ~~~~~~~~~~
168  *
169  * @param as The aerospike instance to use for this operation.
170  * @param err The as_error to be populated if an error occurs.
171  * @param policy The policy to use for this operation. If NULL, then the default policy will be used.
172  * @param query The query to execute against the cluster.
173  * @param callback The callback function to call for each result value.
174  * @param udata User-data to be passed to the callback.
175  *
176  * @return AEROSPIKE_OK on success, otherwise an error.
177  *
178  * @ingroup query_operations
179  */
180 as_status
182  aerospike* as, as_error* err, const as_policy_query* policy, const as_query* query,
183  aerospike_query_foreach_callback callback, void* udata
184  );
185 
186 /**
187  * Asynchronously execute a query and call the listener function for each result item.
188  * Standard secondary index queries are supported, but aggregation queries are not supported
189  * in async mode.
190  *
191  * ~~~~~~~~~~{.c}
192  * bool my_listener(as_error* err, as_record* record, void* udata, as_event_loop* event_loop)
193  * {
194  * if (err) {
195  * printf("Query failed: %d %s\n", err->code, err->message);
196  * return false;
197  * }
198  *
199  * if (! record) {
200  * printf("Query ended\n");
201  * return false;
202  * }
203  *
204  * // Process record
205  * // Do not call as_record_destroy() because the calling function will do that for you.
206  * return true;
207  * }
208  * as_query query;
209  * as_query_init(&query, "test", "demo");
210  * as_query_select(&query, "bin1");
211  * as_query_where(&query, "bin2", as_integer_equals(100));
212  *
213  * if ( aerospike_query_foreach(&as, &err, NULL, &query, callback, NULL) != AEROSPIKE_OK ) {
214  * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line);
215  * }
216  *
217  * as_query_destroy(&query);
218  * ~~~~~~~~~~
219  *
220  * @param as The aerospike instance to use for this operation.
221  * @param err The as_error to be populated if an error occurs.
222  * @param policy The policy to use for this operation. If NULL, then the default policy will be used.
223  * @param query The query to execute against the cluster.
224  * @param listener The function to be called for each returned value.
225  * @param udata User-data to be passed to the callback.
226  * @param event_loop Event loop assigned to run this command. If NULL, an event loop will be choosen by round-robin.
227  *
228  * @return AEROSPIKE_OK if async query succesfully queued. Otherwise an error.
229  *
230  * @ingroup query_operations
231  */
232 as_status
234  aerospike* as, as_error* err, const as_policy_query* policy, const as_query* query,
235  as_async_query_record_listener listener, void* udata, as_event_loop* event_loop
236  );
237 
238 /**
239  * Apply user defined function on records that match the query filter.
240  * Records are not returned to the client.
241  * This asynchronous server call will return before command is complete.
242  * The user can optionally wait for command completion.
243  *
244  * ~~~~~~~~~~{.c}
245  * as_query query;
246  * as_query_init(&query, "test", "demo");
247  * as_query_select(&query, "bin1");
248  * as_query_where(&query, "bin2", as_integer_equals(100));
249  * as_query_apply(&query, "my_lua.lua", "my_lua_function", NULL);
250  * uint64_t query_id = 0;
251  *
252  * if (aerospike_query_background(&as, &err, NULL, &query, &query_id) == AEROSPIKE_OK) {
253  * aerospike_query_wait(as, &err, NULL, &query, query_id, 0);
254  * }
255  * else {
256  * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line);
257  * }
258  *
259  * as_query_destroy(&query);
260  * ~~~~~~~~~~
261  *
262  * @param as The aerospike instance to use for this operation.
263  * @param err The as_error to be populated if an error occurs.
264  * @param policy The policy to use for this operation. If NULL, then the default policy will be used.
265  * @param query The query to execute against the cluster.
266  * @param query_id The id for the query job, which can be used for querying the status of the query.
267  *
268  * @return AEROSPIKE_OK on success, otherwise an error.
269  *
270  * @ingroup query_operations
271  */
272 as_status
274  aerospike* as, as_error* err, const as_policy_write* policy,
275  const as_query* query, uint64_t* query_id
276  );
277 
278 /**
279  * Wait for a background query to be completed by servers.
280  *
281  * @param as The aerospike instance to use for this operation.
282  * @param err The as_error to be populated if an error occurs.
283  * @param policy The info policy to use for this operation. If NULL, then the default policy will be used.
284  * @param query The query that was executed against the cluster.
285  * @param query_id The id for the query job, which can be used for querying the status of the query.
286  * @param interval_ms Polling interval in milliseconds. If zero, 1000 ms is used.
287  *
288  * @return AEROSPIKE_OK on success, otherwise an error.
289  *
290  * @ingroup query_operations
291  */
292 static inline as_status
294  aerospike* as, as_error* err, const as_policy_info* policy,
295  const as_query* query, uint64_t query_id, uint32_t interval_ms
296  )
297 {
298  const char* module = (query->where.size > 0)? "query" : "scan";
299  return aerospike_job_wait(as, err, policy, module, query_id, interval_ms);
300 }
301 
302 /**
303  * Check the progress of a background query running on the database.
304  *
305  * @param as The aerospike instance to use for this operation.
306  * @param err The as_error to be populated if an error occurs.
307  * @param policy The info policy to use for this operation. If NULL, then the default policy will be used.
308  * @param query The query that was executed against the cluster.
309  * @param query_id The id for the query job, which can be used for querying the status of the query.
310  * @param info Information about this background query, to be populated by this operation.
311  *
312  * @return AEROSPIKE_OK on success, otherwise an error.
313  *
314  * @ingroup query_operations
315  */
316 static inline as_status
318  aerospike* as, as_error* err, const as_policy_info* policy,
319  const as_query* query, uint64_t query_id, as_job_info* info
320  )
321 {
322  const char* module = (query->where.size > 0)? "query" : "scan";
323  return aerospike_job_info(as, err, policy, module, query_id, false, info);
324 }
325 
326 #ifdef __cplusplus
327 } // end extern "C"
328 #endif