All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
as_query.h
Go to the documentation of this file.
1 /*
2  * Copyright 2008-2015 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 #pragma GCC diagnostic ignored "-Waddress"
19 
21 #include <aerospike/as_bin.h>
22 #include <aerospike/as_key.h>
23 #include <aerospike/as_list.h>
24 #include <aerospike/as_udf.h>
25 
26 #include <stdarg.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 /******************************************************************************
33  * MACROS
34  *****************************************************************************/
35 
36 /**
37  * Macro for setting setting the STRING_EQUAL predicate.
38  *
39  * ~~~~~~~~~~{.c}
40  * as_query_where(query, "bin1", as_string_equals("abc"));
41  * ~~~~~~~~~~
42  *
43  * @relates as_query
44  */
45 #define as_string_equals(__val) AS_PREDICATE_EQUAL, AS_INDEX_TYPE_DEFAULT, AS_INDEX_STRING, __val
46 
47 /**
48  * Macro for setting setting the INTEGER_EQUAL predicate.
49  *
50  * ~~~~~~~~~~{.c}
51  * as_query_where(query, "bin1", as_integer_equals(123));
52  * ~~~~~~~~~~
53  *
54  * @relates as_query
55  */
56 #define as_integer_equals(__val) AS_PREDICATE_EQUAL, AS_INDEX_TYPE_DEFAULT, AS_INDEX_NUMERIC, (int64_t)__val
57 
58 /**
59  * Macro for setting setting the INTEGER_RANGE predicate.
60  *
61  * ~~~~~~~~~~{.c}
62  * as_query_where(query, "bin1", as_integer_range(1,100));
63  * ~~~~~~~~~~
64  *
65  * @relates as_query
66  * @ingroup query_object
67  */
68 #define as_integer_range(__min, __max) AS_PREDICATE_RANGE, AS_INDEX_TYPE_DEFAULT, AS_INDEX_NUMERIC, (int64_t)__min, (int64_t)__max
69 
70 /**
71  * Macro for setting setting the RANGE predicate.
72  *
73  * ~~~~~~~~~~{.c}
74  * as_query_where(query, "bin1", as_range(LIST,NUMERIC,1,100));
75  * ~~~~~~~~~~
76  *
77  * @relates as_query
78  * @ingroup query_object
79  */
80 #define as_range(indextype, datatype, __min, __max) AS_PREDICATE_RANGE, AS_INDEX_TYPE_ ##indextype, AS_INDEX_ ##datatype, __min, __max
81 
82 /**
83  * Macro for setting setting the CONTAINS predicate.
84  *
85  * ~~~~~~~~~~{.c}
86  * as_query_where(query, "bin1", as_contains(LIST,STRING,"val"));
87  * ~~~~~~~~~~
88  *
89  * @relates as_query
90  * @ingroup query_object
91  */
92 #define as_contains(indextype, datatype, __val) AS_PREDICATE_EQUAL, AS_INDEX_TYPE_ ##indextype, AS_INDEX_ ##datatype, __val
93 
94 /**
95  * Macro for setting setting the EQUALS predicate.
96  *
97  * ~~~~~~~~~~{.c}
98  * as_query_where(query, "bin1", as_equals(NUMERIC,5));
99  * ~~~~~~~~~~
100  *
101  * @relates as_query
102  * @ingroup query_object
103  */
104 #define as_equals(datatype, __val) AS_PREDICATE_EQUAL, AS_INDEX_TYPE_DEFAULT, AS_INDEX_ ##datatype, __val
105 
106 
107 /******************************************************************************
108  * TYPES
109  *****************************************************************************/
110 
111 /**
112  * Union of supported predicates
113  */
114 typedef union as_predicate_value_u {
115 
116  /**
117  * String Value
118  */
119  char * string;
120 
121  /**
122  * Integer Value
123  */
124  int64_t integer;
125 
126  /**
127  * Integer Range Value
128  */
129  struct {
130 
131  /**
132  * Minimum value
133  */
134  int64_t min;
135 
136  /**
137  * Maximum value
138  */
139  int64_t max;
140 
141  } integer_range;
142 
144 
145 /**
146  * The types of predicates supported.
147  */
148 typedef enum as_predicate_type_e {
149 
150  /**
151  * String Equality Predicate.
152  * Requires as_predicate_value.string to be set.
153  */
155 
158 
159 /**
160  * Defines a predicate, including the bin, type of predicate and the value
161  * for the predicate.
162  */
163 typedef struct as_predicate_s {
164 
165  /**
166  * Bin to apply the predicate to
167  */
169 
170  /**
171  * The predicate type, dictates which values to use from the union
172  */
174 
175  /**
176  * The value for the predicate.
177  */
179 
180  /*
181  * The type of data user wants to query
182  */
183 
185 
186  /*
187  * The type of index predicate is on
188  */
190 } as_predicate;
191 
192 /**
193  * Enumerations defining the direction of an ordering.
194  */
195 typedef enum as_order_e {
196 
197  /**
198  * Ascending order
199  */
201 
202  /**
203  * bin should be in ascending order
204  */
206 
207 } as_order;
208 
209 
210 /**
211  * Defines the direction a bin should be ordered by.
212  */
213 typedef struct as_ordering_s {
214 
215  /**
216  * Name of the bin to sort by
217  */
219 
220  /**
221  * Direction of the sort
222  */
224 
225 } as_ordering;
226 
227 /**
228  * Sequence of bins which should be selected during a query.
229  *
230  * Entries can either be initialized on the stack or on the heap.
231  *
232  * Initialization should be performed via a query object, using:
233  * - as_query_select_init()
234  * - as_query_select_inita()
235  */
236 typedef struct as_query_bins_s {
237 
238  /**
239  * @private
240  * If true, then as_query_destroy() will free this instance.
241  */
242  bool _free;
243 
244  /**
245  * Number of entries allocated
246  */
247  uint16_t capacity;
248 
249  /**
250  * Number of entries used
251  */
252  uint16_t size;
253 
254  /**
255  * Sequence of entries
256  */
258 
259 } as_query_bins;
260 
261 /**
262  * Sequence of predicates to be applied to a query.
263  *
264  * Entries can either be initialized on the stack or on the heap.
265  *
266  * Initialization should be performed via a query object, using:
267  * - as_query_where_init()
268  * - as_query_where_inita()
269  */
270 typedef struct as_query_predicates_s {
271 
272  /**
273  * @private
274  * If true, then as_query_destroy() will free this instance.
275  */
276  bool _free;
277 
278  /**
279  * Number of entries allocated
280  */
281  uint16_t capacity;
282 
283  /**
284  * Number of entries used
285  */
286  uint16_t size;
287 
288  /**
289  * Sequence of entries
290  */
292 
294 
295 /**
296  * Sequence of ordering to be applied to a query results.
297  *
298  * Entries can either be initialized on the stack or on the heap.
299  *
300  * Initialization should be performed via a query object, using:
301  * - as_query_orderby_init()
302  * - as_query_orderby_inita()
303  */
304 typedef struct as_query_sort_s {
305 
306  /**
307  * @private
308  * If true, then as_query_destroy() will free this instance.
309  */
310  bool _free;
311 
312  /**
313  * Number of entries allocated
314  */
315  uint16_t capacity;
316 
317  /**
318  * Number of entries used
319  */
320  uint16_t size;
321 
322  /**
323  * Sequence of entries
324  */
326 
328 
329 
330 /**
331  * The as_query object is used define a query to be executed in the datasbase.
332  *
333  * ## Initialization
334  *
335  * Before using an as_query, it must be initialized via either:
336  * - as_query_init()
337  * - as_query_new()
338  *
339  * as_query_init() should be used on a stack allocated as_query. It will
340  * initialize the as_query with the given namespace and set. On success,
341  * it will return a pointer to the initialized as_query. Otherwise, NULL
342  * is returned.
343  *
344  * ~~~~~~~~~~{.c}
345  * as_query query;
346  * as_query_init(&query, "namespace", "set");
347  * ~~~~~~~~~~
348  *
349  * as_query_new() should be used to allocate and initialize a heap allocated
350  * as_query. It will allocate the as_query, then initialized it with the
351  * given namespace and set. On success, it will return a pointer to the
352  * initialized as_query. Otherwise, NULL is returned.
353  *
354  * ~~~~~~~~~~{.c}
355  * as_query * query = as_query_new("namespace", "set");
356  * ~~~~~~~~~~
357  *
358  * ## Destruction
359  *
360  * When you are finished with the as_query, you can destroy it and associated
361  * resources:
362  *
363  * ~~~~~~~~~~{.c}
364  * as_query_destroy(query);
365  * ~~~~~~~~~~
366  *
367  * ## Usage
368  *
369  * The following explains how to use an as_query to build a query.
370  *
371  * ### Selecting Bins
372  *
373  * as_query_select() is used to specify the bins to be selected by the query.
374  *
375  * ~~~~~~~~~~{.c}
376  * as_query_select(query, "bin1");
377  * as_query_select(query, "bin2");
378  * ~~~~~~~~~~
379  *
380  * Before adding bins to select, the select structure must be initialized via
381  * either:
382  * - as_query_select_inita() - Initializes the structure on the stack.
383  * - as_query_select_init() - Initializes the structure on the heap.
384  *
385  * Both functions are given the number of bins to be selected.
386  *
387  * A complete example using as_query_select_inita()
388  *
389  * ~~~~~~~~~~{.c}
390  * as_query_select_inita(query, 2);
391  * as_query_select(query, "bin1");
392  * as_query_select(query, "bin2");
393  * ~~~~~~~~~~
394  *
395  *
396  * ### Predicates on Bins
397  *
398  * as_query_where() is used to specify predicates to be added to the the query.
399  *
400  * **Note:** Currently, a single where predicate is supported. To do more advanced filtering,
401  * you will want to use a UDF to process the result set on the server.
402  *
403  * ~~~~~~~~~~{.c}
404  * as_query_where(query, "bin1", as_string_equals("abc"));
405  * ~~~~~~~~~~
406  *
407  * The predicates that you can apply to a bin include:
408  * - as_string_equals() - Test for string equality.
409  * - as_integer_equals() - Test for integer equality.
410  * - as_integer_range() - Test for integer within a range.
411  *
412  * Before adding predicates, the where structure must be initialized. To
413  * initialize the where structure, you can choose to use one of the following:
414  * - as_query_where_inita() - Initializes the structure on the stack.
415  * - as_query_where_init() - Initializes the structure on the heap.
416  *
417  * Both functions are given the number of predicates to be added.
418  *
419  * A complete example using as_query_where_inita():
420  *
421  * ~~~~~~~~~~{.c}
422  * as_query_where_inita(query, 1);
423  * as_query_where(query, "bin1", as_string_equals("abc"));
424  * ~~~~~~~~~~
425  *
426  *
427  * ### Sorting Results
428  *
429  * as_query_orderby() is used to specify ordering of results of a query.
430  *
431  * ~~~~~~~~~~{.c}
432  * as_query_orderby(query, "bin1", AS_ORDER_ASCENDING);
433  * ~~~~~~~~~~
434  *
435  * The sort order can be:
436  * - `AS_ORDER_ASCENDING`
437  * - `AS_ORDER_DESCENDING`
438  *
439  * Before adding ordering, the orderby structure must be initialized via
440  * either:
441  * - as_query_orderby_inita() - Initializes the structure on the stack.
442  * - as_query_orderby_init() - Initializes the structure on the heap.
443  *
444  * Both functions are given the number of orderings to be added.
445  *
446  * A complete example using as_query_orderby_inita():
447  *
448  * ~~~~~~~~~~{.c}
449  * as_query_orderby_inita(query, 2);
450  * as_query_orderby(query, "bin1", AS_ORDER_ASCENDING);
451  * as_query_orderby(query, "bin2", AS_ORDER_ASCENDING);
452  * ~~~~~~~~~~
453  *
454  * ### Applying a UDF to Query Results
455  *
456  * A UDF can be applied to the results of a query.
457  *
458  * To define the UDF for the query, use as_query_apply().
459  *
460  * ~~~~~~~~~~{.c}
461  * as_query_apply(query, "udf_module", "udf_function", arglist);
462  * ~~~~~~~~~~
463  *
464  * @ingroup client_objects
465  */
466 typedef struct as_query_s {
467 
468  /**
469  * @private
470  * If true, then as_query_destroy() will free this instance.
471  */
472  bool _free;
473 
474  /**
475  * Namespace to be queried.
476  *
477  * Should be initialized via either:
478  * - as_query_init() - To initialize a stack allocated query.
479  * - as_query_new() - To heap allocate and initialize a query.
480  */
482 
483  /**
484  * Set to be queried.
485  *
486  * Should be initialized via either:
487  * - as_query_init() - To initialize a stack allocated query.
488  * - as_query_new() - To heap allocate and initialize a query.
489  */
491 
492  /**
493  * Name of bins to select.
494  *
495  * Use either of the following function to initialize:
496  * - as_query_select_init() - To initialize on the heap.
497  * - as_query_select_inita() - To initialize on the stack.
498  *
499  * Use as_query_select() to populate.
500  */
502 
503  /**
504  * Predicates for filtering.
505  *
506  * Use either of the following function to initialize:
507  * - as_query_where_init() - To initialize on the heap.
508  * - as_query_where_inita() - To initialize on the stack.
509  *
510  * Use as_query_where() to populate.
511  */
513 
514  /**
515  * Bins to order by.
516  *
517  * Use either of the following function to initialize:
518  * - as_query_orderby_init() - To initialize on the heap.
519  * - as_query_orderby_inita() - To initialize on the stack.
520  *
521  * Use as_query_orderby() to populate.
522  */
524 
525  /**
526  * UDF to apply to results of the query
527  *
528  * Should be set via `as_query_apply()`.
529  */
531 
532 } as_query;
533 
534 /******************************************************************************
535  * INSTANCE FUNCTIONS
536  *****************************************************************************/
537 
538 /**
539  * Initialize a stack allocated as_query.
540  *
541  * ~~~~~~~~~~{.c}
542  * as_query query;
543  * as_query_init(&query, "test", "demo");
544  * ~~~~~~~~~~
545  *
546  * @param query The query to initialize.
547  * @param ns The namespace to query.
548  * @param set The set to query.
549  *
550  * @return On success, the initialized query. Otherwise NULL.
551  *
552  * @relates as_query
553  */
554 as_query * as_query_init(as_query * query, const as_namespace ns, const as_set set);
555 
556 /**
557  * Create and initialize a new heap allocated as_query.
558  *
559  * ~~~~~~~~~~{.c}
560  * as_query * query = as_query_new("test", "demo");
561  * ~~~~~~~~~~
562  *
563  * @param ns The namespace to query.
564  * @param set The set to query.
565  *
566  * @return On success, the new query. Otherwise NULL.
567  *
568  * @relates as_query
569  * @ingroup query_object
570  */
571 as_query * as_query_new(const as_namespace ns, const as_set set);
572 
573 /**
574  * Destroy the query and associated resources.
575  *
576  * ~~~~~~~~~~{.c}
577  * as_query_destroy(scan);
578  * ~~~~~~~~~~
579  *
580  * @param query The query to destroy.
581  *
582  * @relates as_query
583  */
584 void as_query_destroy(as_query * query);
585 
586 /******************************************************************************
587  * SELECT FUNCTIONS
588  *****************************************************************************/
589 
590 /**
591  * Initializes `as_query.select` with a capacity of `n` using `alloca`
592  *
593  * For heap allocation, use `as_query_select_init()`.
594  *
595  * ~~~~~~~~~~{.c}
596  * as_query_select_inita(&query, 2);
597  * as_query_select(&query, "bin1");
598  * as_query_select(&query, "bin2");
599  * ~~~~~~~~~~
600  *
601  * @param __query The query to initialize.
602  * @param __n The number of bins to allocate.
603  *
604  * @relates as_query
605  * @ingroup query_object
606  */
607 #define as_query_select_inita(__query, __n) \
608  if ( (__query) != NULL && (__query)->select.entries == NULL ) {\
609  (__query)->select.entries = (as_bin_name *) alloca(__n * sizeof(as_bin_name));\
610  if ( (__query)->select.entries ) { \
611  (__query)->select._free = false;\
612  (__query)->select.capacity = __n;\
613  (__query)->select.size = 0;\
614  }\
615  }
616 
617 /**
618  * Initializes `as_query.select` with a capacity of `n` using `malloc()`.
619  *
620  * For stack allocation, use `as_query_select_inita()`.
621  *
622  * ~~~~~~~~~~{.c}
623  * as_query_select_init(&query, 2);
624  * as_query_select(&query, "bin1");
625  * as_query_select(&query, "bin2");
626  * ~~~~~~~~~~
627  *
628  * @param query The query to initialize.
629  * @param n The number of bins to allocate.
630  *
631  * @return On success, the initialized. Otherwise an error occurred.
632  *
633  * @relates as_query
634  * @ingroup query_object
635  */
636 bool as_query_select_init(as_query * query, uint16_t n);
637 
638 /**
639  * Select bins to be projected from matching records.
640  *
641  * You have to ensure as_query.select has sufficient capacity, prior to
642  * adding a bin. If capacity is sufficient then false is returned.
643  *
644  * ~~~~~~~~~~{.c}
645  * as_query_select_init(&query, 2);
646  * as_query_select(&query, "bin1");
647  * as_query_select(&query, "bin2");
648  * ~~~~~~~~~~
649  *
650  * @param query The query to modify.
651  * @param bin The name of the bin to select.
652  *
653  * @return On success, true. Otherwise an error occurred.
654  *
655  * @relates as_query
656  * @ingroup query_object
657  */
658 bool as_query_select(as_query * query, const char * bin);
659 
660 /******************************************************************************
661  * WHERE FUNCTIONS
662  *****************************************************************************/
663 
664 /**
665  * Initializes `as_query.where` with a capacity of `n` using `alloca()`.
666  *
667  * For heap allocation, use `as_query_where_init()`.
668  *
669  * ~~~~~~~~~~{.c}
670  * as_query_where_inita(&query, 3);
671  * as_query_where(&query, "bin1", as_string_equals("abc"));
672  * as_query_where(&query, "bin2", as_integer_equals(123));
673  * as_query_where(&query, "bin3", as_integer_range(0,123));
674  * ~~~~~~~~~~
675  *
676  * @param __query The query to initialize.
677  * @param __n The number of as_predicate to allocate.
678  *
679  * @return On success, true. Otherwise an error occurred.
680  *
681  * @relates as_query
682  */
683 #define as_query_where_inita(__query, __n) \
684  if ( (__query) != NULL && (__query)->where.entries == NULL ) {\
685  (__query)->where.entries = (as_predicate *) alloca(__n * sizeof(as_predicate));\
686  if ( (__query)->where.entries ) { \
687  (__query)->where._free = false;\
688  (__query)->where.capacity = __n;\
689  (__query)->where.size = 0;\
690  }\
691  }
692 
693 /**
694  * Initializes `as_query.where` with a capacity of `n` using `malloc()`.
695  *
696  * For stack allocation, use `as_query_where_inita()`.
697  *
698  * ~~~~~~~~~~{.c}
699  * as_query_where_init(&query, 3);
700  * as_query_where(&query, "bin1", as_string_equals("abc"));
701  * as_query_where(&query, "bin1", as_integer_equals(123));
702  * as_query_where(&query, "bin1", as_integer_range(0,123));
703  * ~~~~~~~~~~
704  *
705  * @param query The query to initialize.
706  * @param n The number of as_predicate to allocate.
707  *
708  * @return On success, true. Otherwise an error occurred.
709  *
710  * @relates as_query
711  */
712 bool as_query_where_init(as_query * query, uint16_t n);
713 
714 /**
715  * Add a predicate to the query.
716  *
717  * You have to ensure as_query.where has sufficient capacity, prior to
718  * adding a predicate. If capacity is insufficient then false is returned.
719  *
720  * ~~~~~~~~~~{.c}
721  * as_query_where_init(&query, 3);
722  * as_query_where(&query, "bin1", as_string_equals("abc"));
723  * as_query_where(&query, "bin1", as_integer_equals(123));
724  * as_query_where(&query, "bin1", as_integer_range(0,123));
725  * ~~~~~~~~~~
726  *
727  * @param query The query add the predicate to.
728  * @param bin The name of the bin the predicate will apply to.
729  * @param type The type of predicate.
730  * @param itype The type of index.
731  * @param dtype The underlying data type that the index is based on.
732  * @param ... The values for the predicate.
733  *
734  * @return On success, true. Otherwise an error occurred.
735  *
736  * @relates as_query
737  */
738 bool as_query_where(as_query * query, const char * bin, as_predicate_type type, as_index_type itype, as_index_datatype dtype, ... );
739 
740 /******************************************************************************
741  * ORDERBY FUNCTIONS
742  *****************************************************************************/
743 
744 /**
745  * Initializes `as_query.where` with a capacity of `n` using `alloca()`.
746  *
747  * For heap allocation, use `as_query_where_init()`.
748  *
749  * ~~~~~~~~~~{.c}
750  * as_query_orderby_inita(&query, 1);
751  * as_query_orderby(&query, "bin1", AS_ORDER_ASCENDING);
752  * ~~~~~~~~~~
753  *
754  * @param __query The query to initialize.
755  * @param __n The number of as_orders to allocate.
756  *
757  * @return On success, true. Otherwise an error occurred.
758  *
759  * @relates as_query
760  */
761 #define as_query_orderby_inita(__query, __n) \
762  if ( (__query) != NULL && (__query)->orderby.entries == NULL ) {\
763  (__query)->orderby.entries = (as_ordering *) alloca(__n * sizeof(as_ordering));\
764  if ( (__query)->orderby.entries ) { \
765  (__query)->orderby._free = false;\
766  (__query)->orderby.capacity = __n;\
767  (__query)->orderby.size = 0;\
768  }\
769  }
770 
771 /**
772  * Initializes `as_query.orderby` with a capacity of `n` using `malloc()`.
773  *
774  * For stack allocation, use `as_query_orderby_inita()`.
775  *
776  * ~~~~~~~~~~{.c}
777  * as_query_orderby_init(&query, 1);
778  * as_query_orderby(&query, "bin1", AS_ORDER_ASCENDING);
779  * ~~~~~~~~~~
780  *
781  * @param query The query to initialize.
782  * @param n The number of as_orders to allocate.
783  *
784  * @return On success, true. Otherwise an error occurred.
785  *
786  * @relates as_query
787  */
788 bool as_query_orderby_init(as_query * query, uint16_t n);
789 
790 /**
791  * Add a bin to sort by to the query.
792  *
793  * You have to ensure as_query.orderby has sufficient capacity, prior to
794  * adding an ordering. If capacity is insufficient then false is returned.
795  *
796  * ~~~~~~~~~~{.c}
797  * as_query_orderby_init(&query, 1);
798  * as_query_orderby(&query, "bin1", AS_ORDER_ASCENDING);
799  * ~~~~~~~~~~
800  *
801  * @param query The query to modify.
802  * @param bin The name of the bin to sort by.
803  * @param order The sort order: `AS_ORDER_ASCENDING` or `AS_ORDER_DESCENDING`.
804  *
805  * @return On success, true. Otherwise an error occurred.
806  *
807  * @relates as_query
808  */
809 bool as_query_orderby(as_query * query, const char * bin, as_order order);
810 
811 /******************************************************************************
812  * QUERY MODIFIER FUNCTIONS
813  *****************************************************************************/
814 
815 /**
816  * Apply a function to the results of the query.
817  *
818  * ~~~~~~~~~~{.c}
819  * as_query_apply(&query, "my_module", "my_function", NULL);
820  * ~~~~~~~~~~
821  *
822  * @param query The query to apply the function to.
823  * @param module The module containing the function to invoke.
824  * @param function The function in the module to invoke.
825  * @param arglist The arguments to use when calling the function.
826  *
827  * @return On success, true. Otherwise an error occurred.
828  *
829  * @relates as_query
830  */
831 bool as_query_apply(as_query * query, const char * module, const char * function, const as_list * arglist);
832 
833 #ifdef __cplusplus
834 } // end extern "C"
835 #endif