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