1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2009-2017 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "../grn_proc.h"
20#include "../grn_raw_string.h"
21#include "../grn_expr.h"
22#include "../grn_str.h"
23#include "../grn_output.h"
24#include "../grn_util.h"
25#include "../grn_cache.h"
26#include "../grn_ii.h"
27
28#include "../grn_ts.h"
29
30#include <groonga/plugin.h>
31
32#define GRN_SELECT_INTERNAL_VAR_MATCH_COLUMNS "$match_columns"
33
34#define DEFAULT_DRILLDOWN_LIMIT 10
35#define DEFAULT_DRILLDOWN_OUTPUT_COLUMNS "_key, _nsubrecs"
36
37typedef enum {
38 GRN_COLUMN_STAGE_INITIAL,
39 GRN_COLUMN_STAGE_FILTERED,
40 GRN_COLUMN_STAGE_OUTPUT
41} grn_column_stage;
42
43typedef struct {
44 grn_raw_string label;
45 grn_column_stage stage;
46 grn_obj *type;
47 grn_obj_flags flags;
48 grn_raw_string value;
49 struct {
50 grn_raw_string sort_keys;
51 grn_raw_string group_keys;
52 } window;
53} grn_column_data;
54
55typedef struct {
56 grn_hash *initial;
57 grn_hash *filtered;
58 grn_hash *output;
59} grn_columns;
60
61typedef struct {
62 grn_raw_string match_columns;
63 grn_raw_string query;
64 grn_raw_string query_expander;
65 grn_raw_string query_flags;
66 grn_raw_string filter;
67 struct {
68 grn_obj *match_columns;
69 grn_obj *expression;
70 } condition;
71 grn_obj *filtered;
72} grn_filter_data;
73
74typedef struct {
75 grn_raw_string label;
76 grn_filter_data filter;
77 grn_raw_string sort_keys;
78 grn_raw_string output_columns;
79 int offset;
80 int limit;
81 grn_obj *table;
82} grn_slice_data;
83
84typedef struct {
85 grn_raw_string label;
86 grn_raw_string keys;
87 grn_table_sort_key *parsed_keys;
88 int n_parsed_keys;
89 grn_raw_string sort_keys;
90 grn_raw_string output_columns;
91 int offset;
92 int limit;
93 grn_table_group_flags calc_types;
94 grn_raw_string calc_target_name;
95 grn_raw_string filter;
96 grn_raw_string table_name;
97 grn_columns columns;
98 grn_table_group_result result;
99 grn_obj *filtered_result;
100} grn_drilldown_data;
101
102typedef struct _grn_select_output_formatter grn_select_output_formatter;
103
104typedef struct {
105 /* inputs */
106 grn_raw_string table;
107 grn_filter_data filter;
108 grn_raw_string scorer;
109 grn_raw_string sort_keys;
110 grn_raw_string output_columns;
111 int offset;
112 int limit;
113 grn_hash *slices;
114 grn_drilldown_data drilldown;
115 grn_hash *drilldowns;
116 grn_raw_string cache;
117 grn_raw_string match_escalation_threshold;
118 grn_raw_string adjuster;
119 grn_columns columns;
120
121 /* for processing */
122 struct {
123 grn_obj *target;
124 grn_obj *initial;
125 grn_obj *result;
126 grn_obj *sorted;
127 grn_obj *output;
128 } tables;
129 uint16_t cacheable;
130 uint16_t taintable;
131 struct {
132 int n_elements;
133 grn_select_output_formatter *formatter;
134 } output;
135} grn_select_data;
136
137typedef void grn_select_output_slices_label_func(grn_ctx *ctx,
138 grn_select_data *data);
139typedef void grn_select_output_slices_open_func(grn_ctx *ctx,
140 grn_select_data *data,
141 unsigned int n_result_sets);
142typedef void grn_select_output_slices_close_func(grn_ctx *ctx,
143 grn_select_data *data);
144typedef void grn_select_output_slice_label_func(grn_ctx *ctx,
145 grn_select_data *data,
146 grn_slice_data *slice);
147typedef void grn_select_output_drilldowns_label_func(grn_ctx *ctx,
148 grn_select_data *data);
149typedef void grn_select_output_drilldowns_open_func(grn_ctx *ctx,
150 grn_select_data *data,
151 unsigned int n_result_sets);
152typedef void grn_select_output_drilldowns_close_func(grn_ctx *ctx,
153 grn_select_data *data);
154typedef void grn_select_output_drilldown_label_func(grn_ctx *ctx,
155 grn_select_data *data,
156 grn_drilldown_data *drilldown);
157
158struct _grn_select_output_formatter {
159 grn_select_output_slices_label_func *slices_label;
160 grn_select_output_slices_open_func *slices_open;
161 grn_select_output_slices_close_func *slices_close;
162 grn_select_output_slice_label_func *slice_label;
163 grn_select_output_drilldowns_label_func *drilldowns_label;
164 grn_select_output_drilldowns_open_func *drilldowns_open;
165 grn_select_output_drilldowns_close_func *drilldowns_close;
166 grn_select_output_drilldown_label_func *drilldown_label;
167};
168
169grn_rc
170grn_proc_syntax_expand_query(grn_ctx *ctx,
171 const char *query,
172 unsigned int query_len,
173 grn_expr_flags flags,
174 const char *query_expander_name,
175 unsigned int query_expander_name_len,
176 const char *term_column_name,
177 unsigned int term_column_name_len,
178 const char *expanded_term_column_name,
179 unsigned int expanded_term_column_name_len,
180 grn_obj *expanded_query,
181 const char *error_message_tag)
182{
183 grn_obj *query_expander;
184
185 query_expander = grn_ctx_get(ctx,
186 query_expander_name,
187 query_expander_name_len);
188 if (!query_expander) {
189 GRN_PLUGIN_ERROR(ctx,
190 GRN_INVALID_ARGUMENT,
191 "%s nonexistent query expander: <%.*s>",
192 error_message_tag,
193 (int)query_expander_name_len,
194 query_expander_name);
195 return ctx->rc;
196 }
197
198 if (expanded_term_column_name_len == 0) {
199 return grn_expr_syntax_expand_query(ctx, query, query_len, flags,
200 query_expander, expanded_query);
201 }
202
203 if (!grn_obj_is_table(ctx, query_expander)) {
204 grn_obj inspected;
205 GRN_TEXT_INIT(&inspected, 0);
206 grn_inspect(ctx, &inspected, query_expander);
207 GRN_PLUGIN_ERROR(ctx,
208 GRN_INVALID_ARGUMENT,
209 "%s query expander with expanded term column "
210 "must be table: <%.*s>",
211 error_message_tag,
212 (int)GRN_TEXT_LEN(&inspected),
213 GRN_TEXT_VALUE(&inspected));
214 GRN_OBJ_FIN(ctx, &inspected);
215 return ctx->rc;
216 }
217
218 {
219 grn_obj *term_column = NULL;
220 grn_obj *expanded_term_column;
221
222 expanded_term_column = grn_obj_column(ctx,
223 query_expander,
224 expanded_term_column_name,
225 expanded_term_column_name_len);
226 if (!expanded_term_column) {
227 grn_obj inspected;
228 GRN_TEXT_INIT(&inspected, 0);
229 grn_inspect(ctx, &inspected, query_expander);
230 GRN_PLUGIN_ERROR(ctx,
231 GRN_INVALID_ARGUMENT,
232 "%s nonexistent expanded term column: <%.*s>: "
233 "query expander: <%.*s>",
234 error_message_tag,
235 (int)expanded_term_column_name_len,
236 expanded_term_column_name,
237 (int)GRN_TEXT_LEN(&inspected),
238 GRN_TEXT_VALUE(&inspected));
239 GRN_OBJ_FIN(ctx, &inspected);
240 return ctx->rc;
241 }
242
243 if (term_column_name_len > 0) {
244 term_column = grn_obj_column(ctx,
245 query_expander,
246 term_column_name,
247 term_column_name_len);
248 if (!term_column) {
249 grn_obj inspected;
250 GRN_TEXT_INIT(&inspected, 0);
251 grn_inspect(ctx, &inspected, query_expander);
252 GRN_PLUGIN_ERROR(ctx,
253 GRN_INVALID_ARGUMENT,
254 "%s nonexistent term column: <%.*s>: "
255 "query expander: <%.*s>",
256 error_message_tag,
257 (int)term_column_name_len,
258 term_column_name,
259 (int)GRN_TEXT_LEN(&inspected),
260 GRN_TEXT_VALUE(&inspected));
261 GRN_OBJ_FIN(ctx, &inspected);
262 if (grn_obj_is_accessor(ctx, expanded_term_column)) {
263 grn_obj_unlink(ctx, expanded_term_column);
264 }
265 return ctx->rc;
266 }
267 }
268
269 grn_expr_syntax_expand_query_by_table(ctx,
270 query, query_len,
271 flags,
272 term_column,
273 expanded_term_column,
274 expanded_query);
275 if (grn_obj_is_accessor(ctx, term_column)) {
276 grn_obj_unlink(ctx, term_column);
277 }
278 if (grn_obj_is_accessor(ctx, expanded_term_column)) {
279 grn_obj_unlink(ctx, expanded_term_column);
280 }
281 return ctx->rc;
282 }
283}
284
285static grn_table_group_flags
286grn_parse_table_group_calc_types(grn_ctx *ctx,
287 const char *calc_types,
288 unsigned int calc_types_len)
289{
290 grn_table_group_flags flags = 0;
291 const char *calc_types_end = calc_types + calc_types_len;
292
293 while (calc_types < calc_types_end) {
294 if (*calc_types == ',' || *calc_types == ' ') {
295 calc_types += 1;
296 continue;
297 }
298
299#define CHECK_TABLE_GROUP_CALC_TYPE(name)\
300 if (((calc_types_end - calc_types) >= (sizeof(#name) - 1)) &&\
301 (!memcmp(calc_types, #name, sizeof(#name) - 1))) {\
302 flags |= GRN_TABLE_GROUP_CALC_ ## name;\
303 calc_types += sizeof(#name) - 1;\
304 continue;\
305 }
306
307 CHECK_TABLE_GROUP_CALC_TYPE(COUNT);
308 CHECK_TABLE_GROUP_CALC_TYPE(MAX);
309 CHECK_TABLE_GROUP_CALC_TYPE(MIN);
310 CHECK_TABLE_GROUP_CALC_TYPE(SUM);
311 CHECK_TABLE_GROUP_CALC_TYPE(AVG);
312
313#define GRN_TABLE_GROUP_CALC_NONE 0
314 CHECK_TABLE_GROUP_CALC_TYPE(NONE);
315#undef GRN_TABLE_GROUP_CALC_NONE
316
317 GRN_PLUGIN_ERROR(ctx,
318 GRN_INVALID_ARGUMENT,
319 "invalid table group calc type: <%.*s>",
320 (int)(calc_types_end - calc_types),
321 calc_types);
322 return 0;
323#undef CHECK_TABLE_GROUP_CALC_TYPE
324 }
325
326 return flags;
327}
328
329static const char *
330grn_column_stage_name(grn_column_stage stage)
331{
332 switch (stage) {
333 case GRN_COLUMN_STAGE_INITIAL :
334 return "initial";
335 case GRN_COLUMN_STAGE_FILTERED :
336 return "filtered";
337 case GRN_COLUMN_STAGE_OUTPUT :
338 return "output";
339 default :
340 return "unknown";
341 }
342}
343
344static grn_bool
345grn_column_data_init(grn_ctx *ctx,
346 const char *label,
347 size_t label_len,
348 grn_column_stage stage,
349 grn_hash **columns)
350{
351 void *column_raw;
352 grn_column_data *column;
353 int added;
354
355 if (!*columns) {
356 *columns = grn_hash_create(ctx,
357 NULL,
358 GRN_TABLE_MAX_KEY_SIZE,
359 sizeof(grn_column_data),
360 GRN_OBJ_TABLE_HASH_KEY |
361 GRN_OBJ_KEY_VAR_SIZE |
362 GRN_HASH_TINY);
363 }
364 if (!*columns) {
365 return GRN_FALSE;
366 }
367
368 grn_hash_add(ctx,
369 *columns,
370 label,
371 label_len,
372 &column_raw,
373 &added);
374 if (!added) {
375 return GRN_TRUE;
376 }
377
378 column = column_raw;
379 column->label.value = label;
380 column->label.length = label_len;
381 column->stage = stage;
382 column->type = grn_ctx_at(ctx, GRN_DB_TEXT);
383 column->flags = GRN_OBJ_COLUMN_SCALAR;
384 GRN_RAW_STRING_INIT(column->value);
385 GRN_RAW_STRING_INIT(column->window.sort_keys);
386 GRN_RAW_STRING_INIT(column->window.group_keys);
387
388 return GRN_TRUE;
389}
390
391static grn_bool
392grn_column_data_fill(grn_ctx *ctx,
393 grn_column_data *column,
394 grn_obj *type_raw,
395 grn_obj *flags,
396 grn_obj *value,
397 grn_obj *window_sort_keys,
398 grn_obj *window_group_keys)
399{
400 if (type_raw && GRN_TEXT_LEN(type_raw) > 0) {
401 grn_obj *type;
402
403 type = grn_ctx_get(ctx, GRN_TEXT_VALUE(type_raw), GRN_TEXT_LEN(type_raw));
404 if (!type) {
405 GRN_PLUGIN_ERROR(ctx,
406 GRN_INVALID_ARGUMENT,
407 "[select][columns][%s][%.*s] unknown type: <%.*s>",
408 grn_column_stage_name(column->stage),
409 (int)(column->label.length),
410 column->label.value,
411 (int)(GRN_TEXT_LEN(type_raw)),
412 GRN_TEXT_VALUE(type_raw));
413 return GRN_FALSE;
414 }
415 if (!(grn_obj_is_type(ctx, type) || grn_obj_is_table(ctx, type))) {
416 grn_obj inspected;
417 GRN_TEXT_INIT(&inspected, 0);
418 grn_inspect(ctx, &inspected, type);
419 GRN_PLUGIN_ERROR(ctx,
420 GRN_INVALID_ARGUMENT,
421 "[select][columns][%s][%.*s] invalid type: %.*s",
422 grn_column_stage_name(column->stage),
423 (int)(column->label.length),
424 column->label.value,
425 (int)(GRN_TEXT_LEN(&inspected)),
426 GRN_TEXT_VALUE(&inspected));
427 GRN_OBJ_FIN(ctx, &inspected);
428 grn_obj_unlink(ctx, type);
429 return GRN_FALSE;
430 }
431 column->type = type;
432 }
433
434 if (flags && GRN_TEXT_LEN(flags) > 0) {
435 char error_message_tag[GRN_TABLE_MAX_KEY_SIZE];
436
437 grn_snprintf(error_message_tag,
438 GRN_TABLE_MAX_KEY_SIZE,
439 GRN_TABLE_MAX_KEY_SIZE,
440 "[select][columns][%s][%.*s]",
441 grn_column_stage_name(column->stage),
442 (int)(column->label.length),
443 column->label.value);
444 column->flags =
445 grn_proc_column_parse_flags(ctx,
446 error_message_tag,
447 GRN_TEXT_VALUE(flags),
448 GRN_TEXT_VALUE(flags) + GRN_TEXT_LEN(flags));
449 if (ctx->rc != GRN_SUCCESS) {
450 return GRN_FALSE;
451 }
452 }
453
454 GRN_RAW_STRING_FILL(column->value, value);
455 GRN_RAW_STRING_FILL(column->window.sort_keys, window_sort_keys);
456 GRN_RAW_STRING_FILL(column->window.group_keys, window_group_keys);
457
458 return GRN_TRUE;
459}
460
461static grn_bool
462grn_column_data_collect(grn_ctx *ctx,
463 grn_user_data *user_data,
464 grn_hash *columns,
465 const char *prefix_label,
466 size_t prefix_label_len)
467{
468 grn_hash_cursor *cursor = NULL;
469
470 cursor = grn_hash_cursor_open(ctx, columns,
471 NULL, 0, NULL, 0, 0, -1, 0);
472 if (!cursor) {
473 return GRN_FALSE;
474 }
475
476 while (grn_hash_cursor_next(ctx, cursor)) {
477 grn_column_data *column;
478 char key_name[GRN_TABLE_MAX_KEY_SIZE];
479 grn_obj *type = NULL;
480 grn_obj *flags = NULL;
481 grn_obj *value = NULL;
482 struct {
483 grn_obj *sort_keys;
484 grn_obj *group_keys;
485 } window;
486
487 window.sort_keys = NULL;
488 window.group_keys = NULL;
489
490 grn_hash_cursor_get_value(ctx, cursor, (void **)&column);
491
492#define GET_VAR_RAW(parameter_key, name) \
493 if (!name) { \
494 grn_snprintf(key_name, \
495 GRN_TABLE_MAX_KEY_SIZE, \
496 GRN_TABLE_MAX_KEY_SIZE, \
497 "%.*s%s[%.*s]." # name, \
498 (int)prefix_label_len, \
499 prefix_label, \
500 parameter_key, \
501 (int)(column->label.length), \
502 column->label.value); \
503 name = grn_plugin_proc_get_var(ctx, user_data, key_name, -1); \
504 }
505
506#define GET_VAR(name) do { \
507 GET_VAR_RAW("columns", name); \
508 /* For backward compatibility */ \
509 GET_VAR_RAW("column", name); \
510 } while (GRN_FALSE)
511
512 GET_VAR(type);
513 GET_VAR(flags);
514 GET_VAR(value);
515 GET_VAR(window.sort_keys);
516 GET_VAR(window.group_keys);
517
518#undef GET_VAR
519
520#undef GET_VAR_RAW
521
522 grn_column_data_fill(ctx, column,
523 type, flags, value,
524 window.sort_keys,
525 window.group_keys);
526 }
527 grn_hash_cursor_close(ctx, cursor);
528 return GRN_TRUE;
529}
530
531static void
532grn_columns_init(grn_ctx *ctx, grn_columns *columns)
533{
534 columns->initial = NULL;
535 columns->filtered = NULL;
536 columns->output = NULL;
537}
538
539static void
540grn_columns_fin(grn_ctx *ctx, grn_columns *columns)
541{
542 if (columns->initial) {
543 grn_hash_close(ctx, columns->initial);
544 }
545
546 if (columns->filtered) {
547 grn_hash_close(ctx, columns->filtered);
548 }
549
550 if (columns->output) {
551 grn_hash_close(ctx, columns->output);
552 }
553}
554
555static grn_bool
556grn_columns_collect(grn_ctx *ctx,
557 grn_user_data *user_data,
558 grn_columns *columns,
559 const char *prefix,
560 const char *base_prefix,
561 size_t base_prefix_len)
562{
563 grn_obj *vars;
564 grn_table_cursor *cursor;
565 size_t prefix_len;
566 const char *suffix = "].stage";
567 size_t suffix_len;
568
569 vars = grn_plugin_proc_get_vars(ctx, user_data);
570 cursor = grn_table_cursor_open(ctx, vars, NULL, 0, NULL, 0, 0, -1, 0);
571 if (!cursor) {
572 return GRN_FALSE;
573 }
574
575 prefix_len = strlen(prefix);
576 suffix_len = strlen(suffix);
577 while (grn_table_cursor_next(ctx, cursor)) {
578 void *key;
579 char *variable_name;
580 int variable_name_len;
581 char *column_name;
582 size_t column_name_len;
583 void *value_raw;
584 grn_obj *value;
585 grn_column_stage stage;
586 grn_hash **target_columns;
587
588 variable_name_len = grn_table_cursor_get_key(ctx, cursor, &key);
589 variable_name = key;
590 if (variable_name_len < base_prefix_len + prefix_len + suffix_len + 1) {
591 continue;
592 }
593
594 if (base_prefix_len > 0) {
595 if (memcmp(base_prefix, variable_name, base_prefix_len) != 0) {
596 continue;
597 }
598 }
599
600 if (memcmp(prefix, variable_name + base_prefix_len, prefix_len) != 0) {
601 continue;
602 }
603
604 if (memcmp(suffix,
605 variable_name + (variable_name_len - suffix_len),
606 suffix_len) != 0) {
607 continue;
608 }
609
610 grn_table_cursor_get_value(ctx, cursor, &value_raw);
611 value = value_raw;
612 if (GRN_TEXT_EQUAL_CSTRING(value, "initial")) {
613 stage = GRN_COLUMN_STAGE_INITIAL;
614 target_columns = &(columns->initial);
615 } else if (GRN_TEXT_EQUAL_CSTRING(value, "filtered")) {
616 stage = GRN_COLUMN_STAGE_FILTERED;
617 target_columns = &(columns->filtered);
618 } else if (GRN_TEXT_EQUAL_CSTRING(value, "output")) {
619 stage = GRN_COLUMN_STAGE_OUTPUT;
620 target_columns = &(columns->output);
621 } else {
622 continue;
623 }
624
625 column_name = variable_name + base_prefix_len + prefix_len;
626 column_name_len =
627 variable_name_len - base_prefix_len - prefix_len - suffix_len;
628 if (!grn_column_data_init(ctx,
629 column_name,
630 column_name_len,
631 stage,
632 target_columns)) {
633 grn_table_cursor_close(ctx, cursor);
634 return GRN_FALSE;
635 }
636 }
637 grn_table_cursor_close(ctx, cursor);
638
639 return GRN_TRUE;
640}
641
642static grn_bool
643grn_columns_fill(grn_ctx *ctx,
644 grn_user_data *user_data,
645 grn_columns *columns,
646 const char *prefix,
647 size_t prefix_length)
648{
649 if (!grn_columns_collect(ctx, user_data, columns,
650 "columns[", prefix, prefix_length)) {
651 return GRN_FALSE;
652 }
653
654 /* For backward compatibility */
655 if (!grn_columns_collect(ctx, user_data, columns,
656 "column[", prefix, prefix_length)) {
657 return GRN_FALSE;
658 }
659
660 if (columns->initial) {
661 if (!grn_column_data_collect(ctx,
662 user_data,
663 columns->initial,
664 prefix,
665 prefix_length)) {
666 return GRN_FALSE;
667 }
668 }
669
670 if (columns->filtered) {
671 if (!grn_column_data_collect(ctx,
672 user_data,
673 columns->filtered,
674 prefix,
675 prefix_length)) {
676 return GRN_FALSE;
677 }
678 }
679
680 if (columns->output) {
681 if (!grn_column_data_collect(ctx,
682 user_data,
683 columns->output,
684 prefix,
685 prefix_length)) {
686 return GRN_FALSE;
687 }
688 }
689
690 return GRN_TRUE;
691}
692
693static void
694grn_filter_data_init(grn_ctx *ctx, grn_filter_data *data)
695{
696 GRN_RAW_STRING_INIT(data->match_columns);
697 GRN_RAW_STRING_INIT(data->query);
698 GRN_RAW_STRING_INIT(data->query_expander);
699 GRN_RAW_STRING_INIT(data->query_flags);
700 GRN_RAW_STRING_INIT(data->filter);
701 data->condition.match_columns = NULL;
702 data->condition.expression = NULL;
703 data->filtered = NULL;
704}
705
706static void
707grn_filter_data_fin(grn_ctx *ctx, grn_filter_data *data)
708{
709 if (data->filtered) {
710 grn_obj_unlink(ctx, data->filtered);
711 }
712 if (data->condition.expression) {
713 grn_obj_close(ctx, data->condition.expression);
714 }
715 if (data->condition.match_columns) {
716 grn_obj_close(ctx, data->condition.match_columns);
717 }
718}
719
720static void
721grn_filter_data_fill(grn_ctx *ctx,
722 grn_filter_data *data,
723 grn_obj *match_columns,
724 grn_obj *query,
725 grn_obj *query_expander,
726 grn_obj *query_flags,
727 grn_obj *filter)
728{
729 GRN_RAW_STRING_FILL(data->match_columns, match_columns);
730 GRN_RAW_STRING_FILL(data->query, query);
731 GRN_RAW_STRING_FILL(data->query_expander, query_expander);
732 GRN_RAW_STRING_FILL(data->query_flags, query_flags);
733 GRN_RAW_STRING_FILL(data->filter, filter);
734}
735
736static grn_bool
737grn_filter_data_execute(grn_ctx *ctx,
738 grn_filter_data *data,
739 grn_obj *table,
740 const char *tag)
741{
742 grn_obj *variable;
743
744 if (data->query.length == 0 && data->filter.length == 0) {
745 return GRN_TRUE;
746 }
747
748 GRN_EXPR_CREATE_FOR_QUERY(ctx,
749 table,
750 data->condition.expression,
751 variable);
752 if (!data->condition.expression) {
753 grn_rc rc = ctx->rc;
754 if (rc == GRN_SUCCESS) {
755 rc = GRN_NO_MEMORY_AVAILABLE;
756 }
757 GRN_PLUGIN_ERROR(ctx,
758 rc,
759 "%s[condition] "
760 "failed to create expression for condition: %s",
761 tag,
762 ctx->errbuf);
763 return GRN_FALSE;
764 }
765
766 if (data->query.length > 0) {
767 if (data->match_columns.length > 0) {
768 GRN_EXPR_CREATE_FOR_QUERY(ctx,
769 table,
770 data->condition.match_columns,
771 variable);
772 if (!data->condition.match_columns) {
773 grn_rc rc = ctx->rc;
774 if (rc == GRN_SUCCESS) {
775 rc = GRN_NO_MEMORY_AVAILABLE;
776 }
777 GRN_PLUGIN_ERROR(ctx,
778 rc,
779 "%s[match_columns] "
780 "failed to create expression for match columns: "
781 "<%.*s>: %s",
782 tag,
783 (int)(data->match_columns.length),
784 data->match_columns.value,
785 ctx->errbuf);
786 return GRN_FALSE;
787 }
788
789 grn_expr_parse(ctx,
790 data->condition.match_columns,
791 data->match_columns.value,
792 data->match_columns.length,
793 NULL, GRN_OP_MATCH, GRN_OP_AND,
794 GRN_EXPR_SYNTAX_SCRIPT);
795 if (ctx->rc != GRN_SUCCESS) {
796 return GRN_FALSE;
797 }
798 }
799
800 {
801 grn_expr_flags flags;
802 grn_obj query_expander_buf;
803 const char *query = data->query.value;
804 unsigned int query_len = data->query.length;
805
806 flags = GRN_EXPR_SYNTAX_QUERY;
807 if (data->query_flags.length) {
808 flags |= grn_proc_expr_query_flags_parse(ctx,
809 data->query_flags.value,
810 data->query_flags.length,
811 tag);
812 if (ctx->rc != GRN_SUCCESS) {
813 return GRN_FALSE;
814 }
815 } else {
816 flags |= GRN_EXPR_ALLOW_PRAGMA|GRN_EXPR_ALLOW_COLUMN;
817 }
818
819 GRN_TEXT_INIT(&query_expander_buf, 0);
820 if (data->query_expander.length > 0) {
821 grn_rc rc;
822 rc = grn_proc_syntax_expand_query(ctx,
823 data->query.value,
824 data->query.length,
825 flags,
826 data->query_expander.value,
827 data->query_expander.length,
828 NULL, 0,
829 NULL, 0,
830 &query_expander_buf,
831 tag);
832 if (rc == GRN_SUCCESS) {
833 query = GRN_TEXT_VALUE(&query_expander_buf);
834 query_len = GRN_TEXT_LEN(&query_expander_buf);
835 } else {
836 GRN_OBJ_FIN(ctx, &query_expander_buf);
837 return GRN_FALSE;
838 }
839 }
840
841 grn_expr_parse(ctx,
842 data->condition.expression,
843 query,
844 query_len,
845 data->condition.match_columns,
846 GRN_OP_MATCH,
847 GRN_OP_AND,
848 flags);
849 GRN_OBJ_FIN(ctx, &query_expander_buf);
850
851 if (ctx->rc != GRN_SUCCESS) {
852 return GRN_FALSE;
853 }
854 }
855 }
856
857 if (data->filter.length > 0) {
858 grn_expr_parse(ctx,
859 data->condition.expression,
860 data->filter.value,
861 data->filter.length,
862 data->condition.match_columns,
863 GRN_OP_MATCH,
864 GRN_OP_AND,
865 GRN_EXPR_SYNTAX_SCRIPT);
866 if (ctx->rc != GRN_SUCCESS) {
867 return GRN_FALSE;
868 }
869
870 if (data->query.length > 0) {
871 grn_expr_append_op(ctx, data->condition.expression, GRN_OP_AND, 2);
872 }
873
874 if (ctx->rc != GRN_SUCCESS) {
875 return GRN_FALSE;
876 }
877 }
878
879 data->filtered = grn_table_select(ctx,
880 table,
881 data->condition.expression,
882 NULL,
883 GRN_OP_OR);
884
885 return ctx->rc == GRN_SUCCESS;
886}
887
888static void
889grn_slice_data_init(grn_ctx *ctx,
890 grn_slice_data *slice,
891 const char *label,
892 size_t label_len)
893{
894 slice->label.value = label;
895 slice->label.length = label_len;
896 grn_filter_data_init(ctx, &(slice->filter));
897 GRN_RAW_STRING_INIT(slice->sort_keys);
898 GRN_RAW_STRING_INIT(slice->output_columns);
899 slice->offset = 0;
900 slice->limit = GRN_SELECT_DEFAULT_LIMIT;
901 slice->table = NULL;
902}
903
904static void
905grn_slice_data_fin(grn_ctx *ctx, grn_slice_data *slice)
906{
907 grn_filter_data_fin(ctx, &(slice->filter));
908}
909
910static void
911grn_slice_data_fill(grn_ctx *ctx,
912 grn_slice_data *slice,
913 grn_obj *match_columns,
914 grn_obj *query,
915 grn_obj *query_expander,
916 grn_obj *query_flags,
917 grn_obj *filter,
918 grn_obj *sort_keys,
919 grn_obj *output_columns,
920 grn_obj *offset,
921 grn_obj *limit)
922{
923 grn_filter_data_fill(ctx,
924 &(slice->filter),
925 match_columns,
926 query,
927 query_expander,
928 query_flags,
929 filter);
930
931 GRN_RAW_STRING_FILL(slice->sort_keys, sort_keys);
932
933 GRN_RAW_STRING_FILL(slice->output_columns, output_columns);
934 if (slice->output_columns.length == 0) {
935 slice->output_columns.value = GRN_SELECT_DEFAULT_OUTPUT_COLUMNS;
936 slice->output_columns.length = strlen(GRN_SELECT_DEFAULT_OUTPUT_COLUMNS);
937 }
938
939 slice->offset = grn_proc_option_value_int32(ctx, offset, 0);
940 slice->limit = grn_proc_option_value_int32(ctx,
941 limit,
942 GRN_SELECT_DEFAULT_LIMIT);
943}
944
945static void
946grn_drilldown_data_init(grn_ctx *ctx,
947 grn_drilldown_data *drilldown,
948 const char *label,
949 size_t label_len)
950{
951 drilldown->label.value = label;
952 drilldown->label.length = label_len;
953 GRN_RAW_STRING_INIT(drilldown->keys);
954 drilldown->parsed_keys = NULL;
955 drilldown->n_parsed_keys = 0;
956 GRN_RAW_STRING_INIT(drilldown->sort_keys);
957 GRN_RAW_STRING_INIT(drilldown->output_columns);
958 drilldown->offset = 0;
959 drilldown->limit = DEFAULT_DRILLDOWN_LIMIT;
960 drilldown->calc_types = 0;
961 GRN_RAW_STRING_INIT(drilldown->calc_target_name);
962 GRN_RAW_STRING_INIT(drilldown->filter);
963 GRN_RAW_STRING_INIT(drilldown->table_name);
964 grn_columns_init(ctx, &(drilldown->columns));
965 drilldown->result.table = NULL;
966 drilldown->filtered_result = NULL;
967}
968
969static void
970grn_drilldown_data_fin(grn_ctx *ctx, grn_drilldown_data *drilldown)
971{
972 grn_table_group_result *result;
973
974 grn_columns_fin(ctx, &(drilldown->columns));
975
976 if (drilldown->filtered_result) {
977 grn_obj_close(ctx, drilldown->filtered_result);
978 }
979
980 result = &(drilldown->result);
981 if (result->table) {
982 if (result->calc_target) {
983 grn_obj_unlink(ctx, result->calc_target);
984 }
985 if (result->table) {
986 grn_obj_close(ctx, result->table);
987 }
988 }
989}
990
991static void
992grn_drilldown_data_fill(grn_ctx *ctx,
993 grn_drilldown_data *drilldown,
994 grn_obj *keys,
995 grn_obj *sort_keys,
996 grn_obj *output_columns,
997 grn_obj *offset,
998 grn_obj *limit,
999 grn_obj *calc_types,
1000 grn_obj *calc_target,
1001 grn_obj *filter,
1002 grn_obj *table)
1003{
1004 GRN_RAW_STRING_FILL(drilldown->keys, keys);
1005
1006 GRN_RAW_STRING_FILL(drilldown->sort_keys, sort_keys);
1007
1008 GRN_RAW_STRING_FILL(drilldown->output_columns, output_columns);
1009 if (drilldown->output_columns.length == 0) {
1010 drilldown->output_columns.value = DEFAULT_DRILLDOWN_OUTPUT_COLUMNS;
1011 drilldown->output_columns.length = strlen(DEFAULT_DRILLDOWN_OUTPUT_COLUMNS);
1012 }
1013
1014 if (offset && GRN_TEXT_LEN(offset)) {
1015 drilldown->offset =
1016 grn_atoi(GRN_TEXT_VALUE(offset), GRN_BULK_CURR(offset), NULL);
1017 } else {
1018 drilldown->offset = 0;
1019 }
1020
1021 if (limit && GRN_TEXT_LEN(limit)) {
1022 drilldown->limit =
1023 grn_atoi(GRN_TEXT_VALUE(limit), GRN_BULK_CURR(limit), NULL);
1024 } else {
1025 drilldown->limit = DEFAULT_DRILLDOWN_LIMIT;
1026 }
1027
1028 if (calc_types && GRN_TEXT_LEN(calc_types)) {
1029 drilldown->calc_types =
1030 grn_parse_table_group_calc_types(ctx,
1031 GRN_TEXT_VALUE(calc_types),
1032 GRN_TEXT_LEN(calc_types));
1033 } else {
1034 drilldown->calc_types = 0;
1035 }
1036
1037 GRN_RAW_STRING_FILL(drilldown->calc_target_name, calc_target);
1038
1039 GRN_RAW_STRING_FILL(drilldown->filter, filter);
1040
1041 GRN_RAW_STRING_FILL(drilldown->table_name, table);
1042}
1043
1044grn_expr_flags
1045grn_proc_expr_query_flags_parse(grn_ctx *ctx,
1046 const char *query_flags,
1047 size_t query_flags_size,
1048 const char *error_message_tag)
1049{
1050 grn_expr_flags flags = 0;
1051 const char *query_flags_end = query_flags + query_flags_size;
1052
1053 while (query_flags < query_flags_end) {
1054 if (*query_flags == '|' || *query_flags == ' ') {
1055 query_flags += 1;
1056 continue;
1057 }
1058
1059#define CHECK_EXPR_FLAG(name) \
1060 if (((query_flags_end - query_flags) >= (sizeof(#name) - 1)) && \
1061 (memcmp(query_flags, #name, sizeof(#name) - 1) == 0) && \
1062 (((query_flags_end - query_flags) == (sizeof(#name) - 1)) || \
1063 (query_flags[sizeof(#name) - 1] == '|') || \
1064 (query_flags[sizeof(#name) - 1] == ' '))) { \
1065 flags |= GRN_EXPR_ ## name; \
1066 query_flags += sizeof(#name) - 1; \
1067 continue; \
1068 }
1069
1070 CHECK_EXPR_FLAG(ALLOW_PRAGMA);
1071 CHECK_EXPR_FLAG(ALLOW_COLUMN);
1072 CHECK_EXPR_FLAG(ALLOW_UPDATE);
1073 CHECK_EXPR_FLAG(ALLOW_LEADING_NOT);
1074 CHECK_EXPR_FLAG(QUERY_NO_SYNTAX_ERROR);
1075
1076#define GRN_EXPR_NONE 0
1077 CHECK_EXPR_FLAG(NONE);
1078#undef GNR_EXPR_NONE
1079
1080 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
1081 "%s invalid query flag: <%.*s>",
1082 error_message_tag,
1083 (int)(query_flags_end - query_flags),
1084 query_flags);
1085 return 0;
1086#undef CHECK_EXPR_FLAG
1087 }
1088
1089 return flags;
1090}
1091
1092static void
1093grn_select_expression_set_condition(grn_ctx *ctx,
1094 grn_obj *expression,
1095 grn_obj *condition)
1096{
1097 grn_obj *condition_ptr;
1098
1099 if (!expression) {
1100 return;
1101 }
1102
1103 condition_ptr =
1104 grn_expr_get_or_add_var(ctx, expression,
1105 GRN_SELECT_INTERNAL_VAR_CONDITION,
1106 GRN_SELECT_INTERNAL_VAR_CONDITION_LEN);
1107 GRN_PTR_INIT(condition_ptr, 0, GRN_DB_OBJECT);
1108 GRN_PTR_SET(ctx, condition_ptr, condition);
1109}
1110
1111grn_bool
1112grn_proc_select_format_init(grn_ctx *ctx,
1113 grn_obj_format *format,
1114 grn_obj *result_set,
1115 int n_hits,
1116 int offset,
1117 int limit,
1118 const char *columns,
1119 int columns_len,
1120 grn_obj *condition)
1121{
1122 grn_rc rc;
1123
1124 GRN_OBJ_FORMAT_INIT(format, n_hits, offset, limit, offset);
1125 format->flags =
1126 GRN_OBJ_FORMAT_WITH_COLUMN_NAMES|
1127 GRN_OBJ_FORMAT_XML_ELEMENT_RESULTSET;
1128 rc = grn_output_format_set_columns(ctx,
1129 format,
1130 result_set,
1131 columns,
1132 columns_len);
1133 if (rc != GRN_SUCCESS) {
1134 GRN_OBJ_FORMAT_FIN(ctx, format);
1135 return GRN_FALSE;
1136 }
1137
1138 grn_select_expression_set_condition(ctx, format->expression, condition);
1139
1140 return ctx->rc == GRN_SUCCESS;
1141}
1142
1143grn_bool
1144grn_proc_select_format_fin(grn_ctx *ctx, grn_obj_format *format)
1145{
1146 GRN_OBJ_FORMAT_FIN(ctx, format);
1147
1148 return ctx->rc == GRN_SUCCESS;
1149}
1150
1151grn_bool
1152grn_proc_select_output_columns_open(grn_ctx *ctx,
1153 grn_obj_format *format,
1154 grn_obj *res,
1155 int n_hits,
1156 int offset,
1157 int limit,
1158 const char *columns,
1159 int columns_len,
1160 grn_obj *condition,
1161 uint32_t n_additional_elements)
1162{
1163 grn_bool succeeded;
1164
1165 if (!grn_proc_select_format_init(ctx,
1166 format,
1167 res,
1168 n_hits,
1169 offset,
1170 limit,
1171 columns,
1172 columns_len,
1173 condition)) {
1174 return GRN_FALSE;
1175 }
1176
1177 GRN_OUTPUT_RESULT_SET_OPEN(res, format, n_additional_elements);
1178 succeeded = (ctx->rc == GRN_SUCCESS);
1179 if (!succeeded) {
1180 GRN_OUTPUT_RESULT_SET_CLOSE(res, format);
1181 }
1182
1183 return succeeded;
1184}
1185
1186grn_bool
1187grn_proc_select_output_columns_close(grn_ctx *ctx,
1188 grn_obj_format *format,
1189 grn_obj *result_set)
1190{
1191 GRN_OUTPUT_RESULT_SET_CLOSE(result_set, format);
1192
1193 return grn_proc_select_format_fin(ctx, format);
1194}
1195
1196grn_bool
1197grn_proc_select_output_columns(grn_ctx *ctx,
1198 grn_obj *res,
1199 int n_hits,
1200 int offset,
1201 int limit,
1202 const char *columns,
1203 int columns_len,
1204 grn_obj *condition)
1205{
1206 grn_obj_format format;
1207 uint32_t n_additional_elements = 0;
1208
1209 if (!grn_proc_select_output_columns_open(ctx,
1210 &format,
1211 res,
1212 n_hits,
1213 offset,
1214 limit,
1215 columns,
1216 columns_len,
1217 condition,
1218 n_additional_elements)) {
1219 return GRN_FALSE;
1220 }
1221
1222 return grn_proc_select_output_columns_close(ctx, &format, res);
1223}
1224
1225static grn_obj *
1226grn_select_create_all_selected_result_table(grn_ctx *ctx,
1227 grn_obj *table)
1228{
1229 grn_obj *result;
1230 grn_posting posting;
1231
1232 result = grn_table_create(ctx, NULL, 0, NULL,
1233 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
1234 table, NULL);
1235 if (!result) {
1236 return NULL;
1237 }
1238
1239 memset(&posting, 0, sizeof(grn_posting));
1240 GRN_TABLE_EACH_BEGIN(ctx, table, cursor, id) {
1241 posting.rid = id;
1242 grn_ii_posting_add(ctx,
1243 &posting,
1244 (grn_hash *)(result),
1245 GRN_OP_OR);
1246 } GRN_TABLE_EACH_END(ctx, cursor);
1247
1248 return result;
1249}
1250
1251static grn_obj *
1252grn_select_create_no_sort_keys_sorted_table(grn_ctx *ctx,
1253 grn_select_data *data,
1254 grn_obj *table)
1255{
1256 grn_obj *sorted;
1257 grn_table_cursor *cursor;
1258
1259 sorted = grn_table_create(ctx, NULL, 0, NULL,
1260 GRN_OBJ_TABLE_NO_KEY,
1261 NULL,
1262 table);
1263
1264 if (!sorted) {
1265 return NULL;
1266 }
1267
1268 cursor = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
1269 data->offset,
1270 data->limit,
1271 GRN_CURSOR_ASCENDING);
1272 if (cursor) {
1273 grn_id id;
1274 while ((id = grn_table_cursor_next(ctx, cursor))) {
1275 grn_id *value;
1276 if (grn_array_add(ctx, (grn_array *)sorted, (void **)&value)) {
1277 *value = id;
1278 }
1279 }
1280 grn_table_cursor_close(ctx, cursor);
1281 }
1282
1283 return sorted;
1284}
1285
1286
1287static void
1288grn_select_apply_columns(grn_ctx *ctx,
1289 grn_select_data *data,
1290 grn_obj *table,
1291 grn_hash *columns)
1292{
1293 grn_hash_cursor *columns_cursor;
1294
1295 columns_cursor = grn_hash_cursor_open(ctx, columns,
1296 NULL, 0, NULL, 0, 0, -1, 0);
1297 if (!columns_cursor) {
1298 return;
1299 }
1300
1301 while (grn_hash_cursor_next(ctx, columns_cursor) != GRN_ID_NIL) {
1302 grn_column_data *column_data;
1303 grn_obj *column;
1304 grn_obj *expression;
1305 grn_obj *record;
1306
1307 grn_hash_cursor_get_value(ctx, columns_cursor, (void **)&column_data);
1308
1309 column = grn_column_create(ctx,
1310 table,
1311 column_data->label.value,
1312 column_data->label.length,
1313 NULL,
1314 column_data->flags,
1315 column_data->type);
1316 if (!column) {
1317 GRN_PLUGIN_ERROR(ctx,
1318 GRN_INVALID_ARGUMENT,
1319 "[select][column][%s][%.*s] failed to create column: %s",
1320 grn_column_stage_name(column_data->stage),
1321 (int)(column_data->label.length),
1322 column_data->label.value,
1323 ctx->errbuf);
1324 break;
1325 }
1326
1327 GRN_EXPR_CREATE_FOR_QUERY(ctx, table, expression, record);
1328 if (!expression) {
1329 grn_obj_close(ctx, column);
1330 GRN_PLUGIN_ERROR(ctx,
1331 GRN_INVALID_ARGUMENT,
1332 "[select][column][%s][%.*s] "
1333 "failed to create expression to compute value: %s",
1334 grn_column_stage_name(column_data->stage),
1335 (int)(column_data->label.length),
1336 column_data->label.value,
1337 ctx->errbuf);
1338 break;
1339 }
1340 grn_expr_parse(ctx,
1341 expression,
1342 column_data->value.value,
1343 column_data->value.length,
1344 NULL,
1345 GRN_OP_MATCH,
1346 GRN_OP_AND,
1347 GRN_EXPR_SYNTAX_SCRIPT);
1348 if (ctx->rc != GRN_SUCCESS) {
1349 grn_obj_close(ctx, expression);
1350 grn_obj_close(ctx, column);
1351 GRN_PLUGIN_ERROR(ctx,
1352 GRN_INVALID_ARGUMENT,
1353 "[select][column][%s][%.*s] "
1354 "failed to parse value: <%.*s>: %s",
1355 grn_column_stage_name(column_data->stage),
1356 (int)(column_data->label.length),
1357 column_data->label.value,
1358 (int)(column_data->value.length),
1359 column_data->value.value,
1360 ctx->errbuf);
1361 break;
1362 }
1363 grn_select_expression_set_condition(ctx,
1364 expression,
1365 data->filter.condition.expression);
1366
1367 if (column_data->window.sort_keys.length > 0 ||
1368 column_data->window.group_keys.length > 0) {
1369 grn_window_definition definition;
1370 grn_rc rc;
1371
1372 if (column_data->window.sort_keys.length > 0) {
1373 int n_sort_keys;
1374 definition.sort_keys =
1375 grn_table_sort_key_from_str(ctx,
1376 column_data->window.sort_keys.value,
1377 column_data->window.sort_keys.length,
1378 table, &n_sort_keys);
1379 definition.n_sort_keys = n_sort_keys;
1380 if (!definition.sort_keys) {
1381 grn_obj_close(ctx, expression);
1382 grn_obj_close(ctx, column);
1383 GRN_PLUGIN_ERROR(ctx,
1384 GRN_INVALID_ARGUMENT,
1385 "[select][column][%s][%.*s] "
1386 "failed to parse sort keys: %s",
1387 grn_column_stage_name(column_data->stage),
1388 (int)(column_data->label.length),
1389 column_data->label.value,
1390 ctx->errbuf);
1391 break;
1392 }
1393 } else {
1394 definition.sort_keys = NULL;
1395 definition.n_sort_keys = 0;
1396 }
1397
1398 if (column_data->window.group_keys.length > 0) {
1399 int n_group_keys;
1400 definition.group_keys =
1401 grn_table_sort_key_from_str(ctx,
1402 column_data->window.group_keys.value,
1403 column_data->window.group_keys.length,
1404 table, &n_group_keys);
1405 definition.n_group_keys = n_group_keys;
1406 if (!definition.group_keys) {
1407 grn_obj_close(ctx, expression);
1408 grn_obj_close(ctx, column);
1409 if (definition.sort_keys) {
1410 grn_table_sort_key_close(ctx,
1411 definition.sort_keys,
1412 definition.n_sort_keys);
1413 }
1414 GRN_PLUGIN_ERROR(ctx,
1415 GRN_INVALID_ARGUMENT,
1416 "[select][column][%s][%.*s] "
1417 "failed to parse group keys: %s",
1418 grn_column_stage_name(column_data->stage),
1419 (int)(column_data->label.length),
1420 column_data->label.value,
1421 ctx->errbuf);
1422 break;
1423 }
1424 } else {
1425 definition.group_keys = NULL;
1426 definition.n_group_keys = 0;
1427 }
1428
1429 rc = grn_table_apply_window_function(ctx,
1430 table,
1431 column,
1432 &definition,
1433 expression);
1434 if (definition.sort_keys) {
1435 grn_table_sort_key_close(ctx,
1436 definition.sort_keys,
1437 definition.n_sort_keys);
1438 }
1439 if (definition.group_keys) {
1440 grn_table_sort_key_close(ctx,
1441 definition.group_keys,
1442 definition.n_group_keys);
1443 }
1444 if (rc != GRN_SUCCESS) {
1445 grn_obj_close(ctx, expression);
1446 grn_obj_close(ctx, column);
1447 break;
1448 }
1449 } else {
1450 grn_rc rc;
1451 rc = grn_table_apply_expr(ctx, table, column, expression);
1452 if (rc != GRN_SUCCESS) {
1453 grn_obj_close(ctx, expression);
1454 grn_obj_close(ctx, column);
1455 GRN_PLUGIN_ERROR(ctx,
1456 GRN_INVALID_ARGUMENT,
1457 "[select][column][%s][%.*s] "
1458 "failed to apply expression to generate column values: "
1459 "%s",
1460 grn_column_stage_name(column_data->stage),
1461 (int)(column_data->label.length),
1462 column_data->label.value,
1463 ctx->errbuf);
1464 break;
1465 }
1466 }
1467
1468 grn_obj_close(ctx, expression);
1469
1470 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
1471 ":", "columns[%.*s](%d)",
1472 (int)(column_data->label.length),
1473 column_data->label.value,
1474 grn_table_size(ctx, table));
1475 }
1476
1477 grn_hash_cursor_close(ctx, columns_cursor);
1478}
1479
1480static grn_bool
1481grn_select_apply_initial_columns(grn_ctx *ctx,
1482 grn_select_data *data)
1483{
1484 if (!data->columns.initial) {
1485 return GRN_TRUE;
1486 }
1487
1488 data->tables.initial =
1489 grn_select_create_all_selected_result_table(ctx, data->tables.target);
1490 if (!data->tables.initial) {
1491 return GRN_FALSE;
1492 }
1493
1494 grn_select_apply_columns(ctx,
1495 data,
1496 data->tables.initial,
1497 data->columns.initial);
1498
1499 return ctx->rc == GRN_SUCCESS;
1500}
1501
1502static grn_bool
1503grn_select_filter(grn_ctx *ctx,
1504 grn_select_data *data)
1505{
1506 if (!grn_filter_data_execute(ctx,
1507 &(data->filter),
1508 data->tables.initial,
1509 "[select]")) {
1510 return GRN_FALSE;
1511 }
1512
1513 data->tables.result = data->filter.filtered;
1514 if (!data->tables.result) {
1515 data->tables.result = data->tables.initial;
1516 }
1517
1518 {
1519 grn_expr *expression;
1520 expression = (grn_expr *)(data->filter.condition.expression);
1521 if (expression) {
1522 data->cacheable *= expression->cacheable;
1523 data->taintable += expression->taintable;
1524 }
1525 }
1526
1527 return GRN_TRUE;
1528}
1529
1530static grn_bool
1531grn_select_apply_filtered_columns(grn_ctx *ctx,
1532 grn_select_data *data)
1533{
1534 if (!data->columns.filtered) {
1535 return GRN_TRUE;
1536 }
1537
1538 if (data->tables.result == data->tables.initial) {
1539 data->tables.result =
1540 grn_select_create_all_selected_result_table(ctx, data->tables.initial);
1541 if (!data->tables.result) {
1542 return GRN_FALSE;
1543 }
1544 }
1545
1546 grn_select_apply_columns(ctx,
1547 data,
1548 data->tables.result,
1549 data->columns.filtered);
1550
1551 return ctx->rc == GRN_SUCCESS;
1552}
1553
1554static int
1555grn_select_apply_adjuster_execute_ensure_factor(grn_ctx *ctx,
1556 grn_obj *factor_object)
1557{
1558 if (!factor_object) {
1559 return 1;
1560 } else if (factor_object->header.domain == GRN_DB_INT32) {
1561 return GRN_INT32_VALUE(factor_object);
1562 } else {
1563 grn_rc rc;
1564 grn_obj int32_object;
1565 int factor;
1566 GRN_INT32_INIT(&int32_object, 0);
1567 rc = grn_obj_cast(ctx, factor_object, &int32_object, GRN_FALSE);
1568 if (rc == GRN_SUCCESS) {
1569 factor = GRN_INT32_VALUE(&int32_object);
1570 } else {
1571 /* TODO: Log or return error? */
1572 factor = 1;
1573 }
1574 GRN_OBJ_FIN(ctx, &int32_object);
1575 return factor;
1576 }
1577}
1578
1579static void
1580grn_select_apply_adjuster_execute_adjust(grn_ctx *ctx,
1581 grn_obj *table,
1582 grn_obj *column,
1583 grn_obj *value,
1584 grn_obj *factor)
1585{
1586 grn_obj *index;
1587 unsigned int n_indexes;
1588 int factor_value;
1589
1590 n_indexes = grn_column_index(ctx, column, GRN_OP_MATCH, &index, 1, NULL);
1591 if (n_indexes == 0) {
1592 char column_name[GRN_TABLE_MAX_KEY_SIZE];
1593 int column_name_size;
1594 column_name_size = grn_obj_name(ctx, column,
1595 column_name, GRN_TABLE_MAX_KEY_SIZE);
1596 GRN_PLUGIN_ERROR(ctx,
1597 GRN_INVALID_ARGUMENT,
1598 "adjuster requires index column for the target column: "
1599 "<%.*s>",
1600 column_name_size,
1601 column_name);
1602 return;
1603 }
1604
1605 factor_value = grn_select_apply_adjuster_execute_ensure_factor(ctx, factor);
1606
1607 {
1608 grn_search_optarg options;
1609 memset(&options, 0, sizeof(grn_search_optarg));
1610
1611 options.mode = GRN_OP_EXACT;
1612 options.similarity_threshold = 0;
1613 options.max_interval = 0;
1614 options.weight_vector = NULL;
1615 options.vector_size = factor_value;
1616 options.proc = NULL;
1617 options.max_size = 0;
1618 options.scorer = NULL;
1619
1620 grn_obj_search(ctx, index, value, table, GRN_OP_ADJUST, &options);
1621 }
1622}
1623
1624static void
1625grn_select_apply_adjuster_execute(grn_ctx *ctx,
1626 grn_obj *table,
1627 grn_obj *adjuster)
1628{
1629 grn_expr *expr = (grn_expr *)adjuster;
1630 grn_expr_code *code, *code_end;
1631
1632 code = expr->codes;
1633 code_end = expr->codes + expr->codes_curr;
1634 while (code < code_end) {
1635 grn_obj *column, *value, *factor;
1636
1637 if (code->op == GRN_OP_PLUS) {
1638 code++;
1639 continue;
1640 }
1641
1642 column = code->value;
1643 code++;
1644 value = code->value;
1645 code++;
1646 code++; /* op == GRN_OP_MATCH */
1647 if ((code_end - code) >= 2 && code[1].op == GRN_OP_STAR) {
1648 factor = code->value;
1649 code++;
1650 code++; /* op == GRN_OP_STAR */
1651 } else {
1652 factor = NULL;
1653 }
1654 grn_select_apply_adjuster_execute_adjust(ctx, table, column, value, factor);
1655 }
1656}
1657
1658static grn_bool
1659grn_select_apply_adjuster(grn_ctx *ctx,
1660 grn_select_data *data)
1661{
1662 grn_obj *adjuster;
1663 grn_obj *record;
1664 grn_rc rc;
1665
1666 if (data->adjuster.length == 0) {
1667 return GRN_TRUE;
1668 }
1669
1670 GRN_EXPR_CREATE_FOR_QUERY(ctx, data->tables.target, adjuster, record);
1671 if (!adjuster) {
1672 GRN_PLUGIN_ERROR(ctx,
1673 GRN_INVALID_ARGUMENT,
1674 "[select][adjuster] "
1675 "failed to create expression: %s",
1676 ctx->errbuf);
1677 return GRN_FALSE;
1678 }
1679
1680 rc = grn_expr_parse(ctx, adjuster,
1681 data->adjuster.value,
1682 data->adjuster.length,
1683 NULL,
1684 GRN_OP_MATCH, GRN_OP_ADJUST,
1685 GRN_EXPR_SYNTAX_ADJUSTER);
1686 if (rc != GRN_SUCCESS) {
1687 grn_obj_unlink(ctx, adjuster);
1688 GRN_PLUGIN_ERROR(ctx,
1689 rc,
1690 "[select][adjuster] "
1691 "failed to parse: %s",
1692 ctx->errbuf);
1693 return GRN_FALSE;
1694 }
1695
1696 data->cacheable *= ((grn_expr *)adjuster)->cacheable;
1697 data->taintable += ((grn_expr *)adjuster)->taintable;
1698 grn_select_apply_adjuster_execute(ctx, data->tables.result, adjuster);
1699 grn_obj_unlink(ctx, adjuster);
1700
1701 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
1702 ":", "adjust(%d)", grn_table_size(ctx, data->tables.result));
1703
1704 return GRN_TRUE;
1705}
1706
1707static grn_bool
1708grn_select_apply_scorer(grn_ctx *ctx,
1709 grn_select_data *data)
1710{
1711 grn_obj *scorer;
1712 grn_obj *record;
1713 grn_rc rc = GRN_SUCCESS;
1714
1715 if (data->scorer.length == 0) {
1716 return GRN_TRUE;
1717 }
1718
1719 GRN_EXPR_CREATE_FOR_QUERY(ctx, data->tables.result, scorer, record);
1720 if (!scorer) {
1721 GRN_PLUGIN_ERROR(ctx,
1722 GRN_INVALID_ARGUMENT,
1723 "[select][scorer] "
1724 "failed to create expression: %s",
1725 ctx->errbuf);
1726 return GRN_FALSE;
1727 }
1728
1729 rc = grn_expr_parse(ctx,
1730 scorer,
1731 data->scorer.value,
1732 data->scorer.length,
1733 NULL,
1734 GRN_OP_MATCH,
1735 GRN_OP_AND,
1736 GRN_EXPR_SYNTAX_SCRIPT|GRN_EXPR_ALLOW_UPDATE);
1737 if (rc != GRN_SUCCESS) {
1738 grn_obj_unlink(ctx, scorer);
1739 GRN_PLUGIN_ERROR(ctx,
1740 GRN_INVALID_ARGUMENT,
1741 "[select][scorer] "
1742 "failed to parse: %s",
1743 ctx->errbuf);
1744 return GRN_FALSE;
1745 }
1746
1747 data->cacheable *= ((grn_expr *)scorer)->cacheable;
1748 data->taintable += ((grn_expr *)scorer)->taintable;
1749 GRN_TABLE_EACH_BEGIN(ctx, data->tables.result, cursor, id) {
1750 GRN_RECORD_SET(ctx, record, id);
1751 grn_expr_exec(ctx, scorer, 0);
1752 if (ctx->rc) {
1753 rc = ctx->rc;
1754 GRN_PLUGIN_ERROR(ctx,
1755 rc,
1756 "[select][scorer] "
1757 "failed to execute: <%.*s>: %s",
1758 (int)(data->scorer.length),
1759 data->scorer.value,
1760 ctx->errbuf);
1761 break;
1762 }
1763 } GRN_TABLE_EACH_END(ctx, cursor);
1764 grn_obj_unlink(ctx, scorer);
1765
1766 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
1767 ":", "score(%d)", grn_table_size(ctx, data->tables.result));
1768
1769 return rc == GRN_SUCCESS;
1770}
1771
1772static grn_bool
1773grn_select_sort(grn_ctx *ctx,
1774 grn_select_data *data)
1775{
1776 grn_table_sort_key *keys;
1777 uint32_t n_keys;
1778
1779 if (data->sort_keys.length == 0) {
1780 return GRN_TRUE;
1781 }
1782
1783 keys = grn_table_sort_key_from_str(ctx,
1784 data->sort_keys.value,
1785 data->sort_keys.length,
1786 data->tables.result,
1787 &n_keys);
1788 if (!keys) {
1789 if (ctx->rc == GRN_SUCCESS) {
1790 return GRN_TRUE;
1791 } else {
1792 GRN_PLUGIN_ERROR(ctx,
1793 ctx->rc,
1794 "[select][sort] "
1795 "failed to parse: <%.*s>: %s",
1796 (int)(data->sort_keys.length),
1797 data->sort_keys.value,
1798 ctx->errbuf);
1799 return GRN_FALSE;
1800 }
1801 }
1802
1803 data->tables.sorted = grn_table_create(ctx, NULL, 0, NULL,
1804 GRN_OBJ_TABLE_NO_KEY,
1805 NULL,
1806 data->tables.result);
1807 if (!data->tables.sorted) {
1808 GRN_PLUGIN_ERROR(ctx,
1809 ctx->rc,
1810 "[select][sort] "
1811 "failed to create table to store sorted record: "
1812 "<%.*s>: %s",
1813 (int)(data->sort_keys.length),
1814 data->sort_keys.value,
1815 ctx->errbuf);
1816 return GRN_FALSE;
1817 }
1818
1819 grn_table_sort(ctx,
1820 data->tables.result,
1821 data->offset,
1822 data->limit,
1823 data->tables.sorted,
1824 keys,
1825 n_keys);
1826
1827 grn_table_sort_key_close(ctx, keys, n_keys);
1828
1829 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
1830 ":", "sort(%d)", data->limit);
1831
1832 return ctx->rc == GRN_SUCCESS;
1833}
1834
1835static grn_bool
1836grn_select_apply_output_columns(grn_ctx *ctx,
1837 grn_select_data *data)
1838{
1839 if (!data->columns.output) {
1840 return GRN_TRUE;
1841 }
1842
1843 if (!data->tables.sorted) {
1844 data->tables.sorted =
1845 grn_select_create_no_sort_keys_sorted_table(ctx,
1846 data,
1847 data->tables.result);
1848 if (!data->tables.sorted) {
1849 return GRN_FALSE;
1850 }
1851 }
1852
1853 grn_select_apply_columns(ctx,
1854 data,
1855 data->tables.sorted,
1856 data->columns.output);
1857
1858 return ctx->rc == GRN_SUCCESS;
1859}
1860
1861static grn_bool
1862grn_select_output_match_open(grn_ctx *ctx,
1863 grn_select_data *data,
1864 grn_obj_format *format,
1865 uint32_t n_additional_elements)
1866{
1867 grn_bool succeeded = GRN_TRUE;
1868 int offset;
1869 grn_obj *output_table;
1870
1871 if (data->tables.sorted) {
1872 offset = 0;
1873 output_table = data->tables.sorted;
1874 } else {
1875 offset = data->offset;
1876 output_table = data->tables.result;
1877 }
1878 succeeded =
1879 grn_proc_select_output_columns_open(ctx,
1880 format,
1881 output_table,
1882 grn_table_size(ctx, data->tables.result),
1883 offset,
1884 data->limit,
1885 data->output_columns.value,
1886 data->output_columns.length,
1887 data->filter.condition.expression,
1888 n_additional_elements);
1889 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
1890 ":", "output(%d)", data->limit);
1891
1892 return succeeded;
1893}
1894
1895static grn_bool
1896grn_select_output_match_close(grn_ctx *ctx,
1897 grn_select_data *data,
1898 grn_obj_format *format)
1899{
1900 grn_obj *output_table;
1901
1902 if (data->tables.sorted) {
1903 output_table = data->tables.sorted;
1904 } else {
1905 output_table = data->tables.result;
1906 }
1907
1908 return grn_proc_select_output_columns_close(ctx, format, output_table);
1909}
1910
1911static grn_bool
1912grn_select_output_match(grn_ctx *ctx, grn_select_data *data)
1913{
1914 grn_obj_format format;
1915 uint32_t n_additional_elements = 0;
1916
1917 if (!grn_select_output_match_open(ctx, data, &format, n_additional_elements)) {
1918 return GRN_FALSE;
1919 }
1920
1921 return grn_select_output_match_close(ctx, data, &format);
1922}
1923
1924static grn_bool
1925grn_select_slice_execute(grn_ctx *ctx,
1926 grn_select_data *data,
1927 grn_obj *table,
1928 grn_slice_data *slice)
1929{
1930 char tag[GRN_TABLE_MAX_KEY_SIZE];
1931 grn_filter_data *filter;
1932
1933 grn_snprintf(tag, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
1934 "[select][slices][%.*s]",
1935 (int)(slice->label.length),
1936 slice->label.value);
1937 filter = &(slice->filter);
1938 if (filter->query.length == 0 && filter->filter.length == 0) {
1939 GRN_PLUGIN_ERROR(ctx,
1940 GRN_INVALID_ARGUMENT,
1941 "%s slice requires query or filter",
1942 tag);
1943 return GRN_FALSE;
1944 }
1945
1946 if (!grn_filter_data_execute(ctx, filter, table, tag)) {
1947 return GRN_FALSE;
1948 }
1949
1950 slice->table = filter->filtered;
1951
1952 return GRN_TRUE;
1953}
1954
1955static grn_bool
1956grn_select_slices_execute(grn_ctx *ctx,
1957 grn_select_data *data,
1958 grn_obj *table,
1959 grn_hash *slices)
1960{
1961 grn_bool succeeded = GRN_TRUE;
1962
1963 GRN_HASH_EACH_BEGIN(ctx, slices, cursor, id) {
1964 grn_slice_data *slice;
1965
1966 grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
1967 if (!grn_select_slice_execute(ctx, data, table, slice)) {
1968 succeeded = GRN_FALSE;
1969 break;
1970 }
1971 } GRN_HASH_EACH_END(ctx, cursor);
1972
1973 return succeeded;
1974}
1975
1976static grn_bool
1977grn_select_prepare_slices(grn_ctx *ctx,
1978 grn_select_data *data)
1979{
1980 if (!data->slices) {
1981 return GRN_TRUE;
1982 }
1983
1984 if (!grn_select_slices_execute(ctx, data, data->tables.result, data->slices)) {
1985 return GRN_FALSE;
1986 }
1987
1988 data->output.n_elements += 1;
1989
1990 return GRN_TRUE;
1991}
1992
1993static grn_bool
1994grn_select_output_slices(grn_ctx *ctx,
1995 grn_select_data *data)
1996{
1997 grn_bool succeeded = GRN_TRUE;
1998 unsigned int n_available_results = 0;
1999
2000 if (!data->slices) {
2001 return GRN_TRUE;
2002 }
2003
2004 data->output.formatter->slices_label(ctx, data);
2005
2006 GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
2007 grn_slice_data *slice;
2008
2009 grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
2010 if (slice->table) {
2011 n_available_results++;
2012 }
2013 } GRN_HASH_EACH_END(ctx, cursor);
2014
2015 data->output.formatter->slices_open(ctx, data, n_available_results);
2016
2017 GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
2018 grn_slice_data *slice;
2019 uint32_t n_hits;
2020 int offset;
2021 int limit;
2022
2023 grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
2024 if (!slice->table) {
2025 continue;
2026 }
2027
2028 n_hits = grn_table_size(ctx, slice->table);
2029
2030 offset = slice->offset;
2031 limit = slice->limit;
2032 grn_normalize_offset_and_limit(ctx, n_hits, &offset, &limit);
2033
2034 if (slice->sort_keys.length > 0) {
2035 grn_table_sort_key *sort_keys;
2036 uint32_t n_sort_keys;
2037 sort_keys = grn_table_sort_key_from_str(ctx,
2038 slice->sort_keys.value,
2039 slice->sort_keys.length,
2040 slice->table, &n_sort_keys);
2041 if (sort_keys) {
2042 grn_obj *sorted;
2043 sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY,
2044 NULL, slice->table);
2045 if (sorted) {
2046 grn_table_sort(ctx, slice->table, offset, limit,
2047 sorted, sort_keys, n_sort_keys);
2048 data->output.formatter->slice_label(ctx, data, slice);
2049 if (!grn_proc_select_output_columns(ctx,
2050 sorted,
2051 n_hits,
2052 0,
2053 limit,
2054 slice->output_columns.value,
2055 slice->output_columns.length,
2056 slice->filter.condition.expression)) {
2057 succeeded = GRN_FALSE;
2058 }
2059 grn_obj_unlink(ctx, sorted);
2060 }
2061 grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
2062 } else {
2063 succeeded = GRN_FALSE;
2064 }
2065 } else {
2066 data->output.formatter->slice_label(ctx, data, slice);
2067 if (!grn_proc_select_output_columns(ctx,
2068 slice->table,
2069 n_hits,
2070 offset,
2071 limit,
2072 slice->output_columns.value,
2073 slice->output_columns.length,
2074 slice->filter.condition.expression)) {
2075 succeeded = GRN_FALSE;
2076 }
2077 }
2078
2079 if (!succeeded) {
2080 break;
2081 }
2082
2083 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
2084 ":", "slice(%d)[%.*s]",
2085 n_hits,
2086 (int)(slice->label.length),
2087 slice->label.value);
2088 } GRN_HASH_EACH_END(ctx, cursor);
2089
2090 data->output.formatter->slices_close(ctx, data);
2091
2092 return succeeded;
2093}
2094
2095static grn_bool
2096grn_select_drilldown_execute(grn_ctx *ctx,
2097 grn_select_data *data,
2098 grn_obj *table,
2099 grn_hash *drilldowns,
2100 grn_id id)
2101{
2102 grn_table_sort_key *keys = NULL;
2103 unsigned int n_keys = 0;
2104 grn_obj *target_table = table;
2105 grn_drilldown_data *drilldown;
2106 grn_table_group_result *result;
2107
2108 drilldown =
2109 (grn_drilldown_data *)grn_hash_get_value_(ctx, drilldowns, id, NULL);
2110 result = &(drilldown->result);
2111
2112 result->limit = 1;
2113 result->flags = GRN_TABLE_GROUP_CALC_COUNT;
2114 result->op = 0;
2115 result->max_n_subrecs = 0;
2116 result->key_begin = 0;
2117 result->key_end = 0;
2118 if (result->calc_target) {
2119 grn_obj_unlink(ctx, result->calc_target);
2120 }
2121 result->calc_target = NULL;
2122
2123 if (drilldown->table_name.length > 0) {
2124 grn_id dependent_id;
2125 dependent_id = grn_hash_get(ctx,
2126 drilldowns,
2127 drilldown->table_name.value,
2128 drilldown->table_name.length,
2129 NULL);
2130 if (dependent_id == GRN_ID_NIL) {
2131 if (data->slices) {
2132 grn_slice_data *slice;
2133 dependent_id = grn_hash_get(ctx,
2134 data->slices,
2135 drilldown->table_name.value,
2136 drilldown->table_name.length,
2137 NULL);
2138 if (dependent_id) {
2139 slice =
2140 (grn_slice_data *)grn_hash_get_value_(ctx, data->slices,
2141 dependent_id, NULL);
2142 target_table = slice->table;
2143 }
2144 }
2145 if (dependent_id == GRN_ID_NIL) {
2146 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
2147 "[select][drilldowns][%.*s][table] "
2148 "nonexistent label: <%.*s>",
2149 (int)(drilldown->label.length),
2150 drilldown->label.value,
2151 (int)(drilldown->table_name.length),
2152 drilldown->table_name.value);
2153 return GRN_FALSE;
2154 }
2155 } else {
2156 grn_drilldown_data *dependent_drilldown;
2157 grn_table_group_result *dependent_result;
2158
2159 dependent_drilldown =
2160 (grn_drilldown_data *)grn_hash_get_value_(ctx,
2161 drilldowns,
2162 dependent_id,
2163 NULL);
2164 dependent_result = &(dependent_drilldown->result);
2165 target_table = dependent_result->table;
2166 }
2167 }
2168
2169 if (drilldown->parsed_keys) {
2170 result->key_end = drilldown->n_parsed_keys;
2171 } else if (drilldown->keys.length > 0) {
2172 keys = grn_table_sort_key_from_str(ctx,
2173 drilldown->keys.value,
2174 drilldown->keys.length,
2175 target_table, &n_keys);
2176 if (!keys) {
2177 GRN_PLUGIN_CLEAR_ERROR(ctx);
2178 return GRN_FALSE;
2179 }
2180
2181 result->key_end = n_keys - 1;
2182 if (n_keys > 1) {
2183 result->max_n_subrecs = 1;
2184 }
2185 }
2186
2187 if (drilldown->calc_target_name.length > 0) {
2188 result->calc_target = grn_obj_column(ctx, target_table,
2189 drilldown->calc_target_name.value,
2190 drilldown->calc_target_name.length);
2191 }
2192 if (result->calc_target) {
2193 result->flags |= drilldown->calc_types;
2194 }
2195
2196 if (drilldown->parsed_keys) {
2197 grn_table_group(ctx,
2198 target_table,
2199 drilldown->parsed_keys,
2200 drilldown->n_parsed_keys,
2201 result,
2202 1);
2203 } else {
2204 grn_table_group(ctx, target_table, keys, n_keys, result, 1);
2205 }
2206
2207 if (keys) {
2208 grn_table_sort_key_close(ctx, keys, n_keys);
2209 }
2210
2211 if (!result->table) {
2212 return GRN_FALSE;
2213 }
2214
2215 if (drilldown->columns.initial) {
2216 grn_select_apply_columns(ctx,
2217 data,
2218 result->table,
2219 drilldown->columns.initial);
2220 }
2221
2222 if (drilldown->filter.length > 0) {
2223 grn_obj *expression;
2224 grn_obj *record;
2225 GRN_EXPR_CREATE_FOR_QUERY(ctx, result->table, expression, record);
2226 if (!expression) {
2227 GRN_PLUGIN_ERROR(ctx,
2228 GRN_INVALID_ARGUMENT,
2229 "[select][drilldowns]%s%.*s%s[filter] "
2230 "failed to create expression for filter: %s",
2231 drilldown->label.length > 0 ? "[" : "",
2232 (int)(drilldown->label.length),
2233 drilldown->label.value,
2234 drilldown->label.length > 0 ? "]" : "",
2235 ctx->errbuf);
2236 return GRN_FALSE;
2237 }
2238 grn_expr_parse(ctx,
2239 expression,
2240 drilldown->filter.value,
2241 drilldown->filter.length,
2242 NULL,
2243 GRN_OP_MATCH,
2244 GRN_OP_AND,
2245 GRN_EXPR_SYNTAX_SCRIPT);
2246 if (ctx->rc != GRN_SUCCESS) {
2247 grn_obj_close(ctx, expression);
2248 GRN_PLUGIN_ERROR(ctx,
2249 GRN_INVALID_ARGUMENT,
2250 "[select][drilldowns]%s%.*s%s[filter] "
2251 "failed to parse filter: <%.*s>: %s",
2252 drilldown->label.length > 0 ? "[" : "",
2253 (int)(drilldown->label.length),
2254 drilldown->label.value,
2255 drilldown->label.length > 0 ? "]" : "",
2256 (int)(drilldown->filter.length),
2257 drilldown->filter.value,
2258 ctx->errbuf);
2259 return GRN_FALSE;
2260 }
2261 drilldown->filtered_result = grn_table_select(ctx,
2262 result->table,
2263 expression,
2264 NULL,
2265 GRN_OP_OR);
2266 if (ctx->rc != GRN_SUCCESS) {
2267 grn_obj_close(ctx, expression);
2268 if (drilldown->filtered_result) {
2269 grn_obj_close(ctx, drilldown->filtered_result);
2270 drilldown->filtered_result = NULL;
2271 }
2272 GRN_PLUGIN_ERROR(ctx,
2273 GRN_INVALID_ARGUMENT,
2274 "[select][drilldowns]%s%.*s%s[filter] "
2275 "failed to execute filter: <%.*s>: %s",
2276 drilldown->label.length > 0 ? "[" : "",
2277 (int)(drilldown->label.length),
2278 drilldown->label.value,
2279 drilldown->label.length > 0 ? "]" : "",
2280 (int)(drilldown->filter.length),
2281 drilldown->filter.value,
2282 ctx->errbuf);
2283 return GRN_FALSE;
2284 }
2285 grn_obj_close(ctx, expression);
2286 }
2287
2288 {
2289 unsigned int n_hits;
2290
2291 if (drilldown->filtered_result) {
2292 n_hits = grn_table_size(ctx, drilldown->filtered_result);
2293 } else {
2294 n_hits = grn_table_size(ctx, result->table);
2295 }
2296 if (data->drilldown.keys.length == 0) {
2297 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
2298 ":", "drilldowns[%.*s](%u)",
2299 (int)(drilldown->label.length),
2300 drilldown->label.value,
2301 n_hits);
2302 } else {
2303 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
2304 ":", "drilldown(%u)",
2305 n_hits);
2306 }
2307 }
2308
2309 return GRN_TRUE;
2310}
2311
2312typedef enum {
2313 TSORT_STATUS_NOT_VISITED,
2314 TSORT_STATUS_VISITING,
2315 TSORT_STATUS_VISITED
2316} tsort_status;
2317
2318static grn_bool
2319drilldown_tsort_visit(grn_ctx *ctx,
2320 grn_hash *drilldowns,
2321 tsort_status *statuses,
2322 grn_obj *ids,
2323 grn_id id)
2324{
2325 grn_bool cycled = GRN_TRUE;
2326 uint32_t index = id - 1;
2327
2328 switch (statuses[index]) {
2329 case TSORT_STATUS_VISITING :
2330 cycled = GRN_TRUE;
2331 break;
2332 case TSORT_STATUS_VISITED :
2333 cycled = GRN_FALSE;
2334 break;
2335 case TSORT_STATUS_NOT_VISITED :
2336 cycled = GRN_FALSE;
2337 statuses[index] = TSORT_STATUS_VISITING;
2338 {
2339 grn_drilldown_data *drilldown;
2340 drilldown =
2341 (grn_drilldown_data *)grn_hash_get_value_(ctx, drilldowns, id, NULL);
2342 if (drilldown->table_name.length > 0) {
2343 grn_id dependent_id;
2344 dependent_id = grn_hash_get(ctx, drilldowns,
2345 drilldown->table_name.value,
2346 drilldown->table_name.length,
2347 NULL);
2348 if (dependent_id != GRN_ID_NIL) {
2349 cycled = drilldown_tsort_visit(ctx,
2350 drilldowns,
2351 statuses,
2352 ids,
2353 dependent_id);
2354 if (cycled) {
2355 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
2356 "[select][drilldowns][%.*s][table] "
2357 "cycled dependency: <%.*s>",
2358 (int)(drilldown->label.length),
2359 drilldown->label.value,
2360 (int)(drilldown->table_name.length),
2361 drilldown->table_name.value);
2362 }
2363 }
2364 }
2365 }
2366 if (!cycled) {
2367 statuses[index] = TSORT_STATUS_VISITED;
2368 GRN_RECORD_PUT(ctx, ids, id);
2369 }
2370 break;
2371 }
2372
2373 return cycled;
2374}
2375
2376static grn_bool
2377drilldown_tsort_body(grn_ctx *ctx,
2378 grn_hash *drilldowns,
2379 tsort_status *statuses,
2380 grn_obj *ids)
2381{
2382 grn_bool succeeded = GRN_TRUE;
2383
2384 GRN_HASH_EACH_BEGIN(ctx, drilldowns, cursor, id) {
2385 if (drilldown_tsort_visit(ctx, drilldowns, statuses, ids, id)) {
2386 succeeded = GRN_FALSE;
2387 break;
2388 }
2389 } GRN_HASH_EACH_END(ctx, cursor);
2390
2391 return succeeded;
2392}
2393
2394static void
2395drilldown_tsort_init(grn_ctx *ctx,
2396 tsort_status *statuses,
2397 size_t n_statuses)
2398{
2399 size_t i;
2400 for (i = 0; i < n_statuses; i++) {
2401 statuses[i] = TSORT_STATUS_NOT_VISITED;
2402 }
2403}
2404
2405static grn_bool
2406drilldown_tsort(grn_ctx *ctx,
2407 grn_hash *drilldowns,
2408 grn_obj *ids)
2409{
2410 tsort_status *statuses;
2411 size_t n_statuses;
2412 grn_bool succeeded;
2413
2414 n_statuses = grn_hash_size(ctx, drilldowns);
2415 statuses = GRN_PLUGIN_MALLOCN(ctx, tsort_status, n_statuses);
2416 if (!statuses) {
2417 return GRN_FALSE;
2418 }
2419
2420 drilldown_tsort_init(ctx, statuses, n_statuses);
2421 succeeded = drilldown_tsort_body(ctx, drilldowns, statuses, ids);
2422 GRN_PLUGIN_FREE(ctx, statuses);
2423 return succeeded;
2424}
2425
2426static grn_bool
2427grn_select_drilldowns_execute(grn_ctx *ctx,
2428 grn_select_data *data)
2429{
2430 grn_bool succeeded = GRN_TRUE;
2431 grn_obj tsorted_ids;
2432 size_t i;
2433 size_t n_drilldowns;
2434
2435 GRN_RECORD_INIT(&tsorted_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
2436 if (!drilldown_tsort(ctx, data->drilldowns, &tsorted_ids)) {
2437 succeeded = GRN_FALSE;
2438 goto exit;
2439 }
2440
2441 n_drilldowns = GRN_BULK_VSIZE(&tsorted_ids) / sizeof(grn_id);
2442 for (i = 0; i < n_drilldowns; i++) {
2443 grn_id id;
2444
2445 id = GRN_RECORD_VALUE_AT(&tsorted_ids, i);
2446 if (!grn_select_drilldown_execute(ctx,
2447 data,
2448 data->tables.result,
2449 data->drilldowns,
2450 id)) {
2451 if (ctx->rc != GRN_SUCCESS) {
2452 succeeded = GRN_FALSE;
2453 break;
2454 }
2455 }
2456 }
2457
2458exit :
2459 GRN_OBJ_FIN(ctx, &tsorted_ids);
2460
2461 return succeeded;
2462}
2463
2464static grn_drilldown_data *
2465grn_select_data_drilldowns_add(grn_ctx *ctx,
2466 grn_select_data *data,
2467 const char *label,
2468 size_t label_len)
2469{
2470 grn_drilldown_data *drilldown = NULL;
2471 int added;
2472
2473 if (!data->drilldowns) {
2474 data->drilldowns = grn_hash_create(ctx,
2475 NULL,
2476 GRN_TABLE_MAX_KEY_SIZE,
2477 sizeof(grn_drilldown_data),
2478 GRN_OBJ_TABLE_HASH_KEY |
2479 GRN_OBJ_KEY_VAR_SIZE |
2480 GRN_HASH_TINY);
2481 if (!data->drilldowns) {
2482 GRN_PLUGIN_ERROR(ctx,
2483 GRN_INVALID_ARGUMENT,
2484 "[select][drilldowns] "
2485 "failed to allocate drilldowns data: %s",
2486 ctx->errbuf);
2487 return NULL;
2488 }
2489 }
2490
2491 grn_hash_add(ctx,
2492 data->drilldowns,
2493 label,
2494 label_len,
2495 (void **)&drilldown,
2496 &added);
2497 if (added) {
2498 grn_drilldown_data_init(ctx, drilldown, label, label_len);
2499 }
2500
2501 return drilldown;
2502}
2503
2504static grn_bool
2505grn_select_prepare_drilldowns(grn_ctx *ctx,
2506 grn_select_data *data)
2507{
2508 if (data->drilldown.keys.length > 0) {
2509 data->drilldown.parsed_keys =
2510 grn_table_sort_key_from_str(ctx,
2511 data->drilldown.keys.value,
2512 data->drilldown.keys.length,
2513 data->tables.result,
2514 &(data->drilldown.n_parsed_keys));
2515 if (data->drilldown.parsed_keys) {
2516 int i;
2517 grn_obj buffer;
2518
2519 GRN_TEXT_INIT(&buffer, 0);
2520 for (i = 0; i < data->drilldown.n_parsed_keys; i++) {
2521 grn_drilldown_data *drilldown;
2522
2523 GRN_BULK_REWIND(&buffer);
2524 grn_text_printf(ctx, &buffer, "drilldown%d", i);
2525 drilldown = grn_select_data_drilldowns_add(ctx,
2526 data,
2527 GRN_TEXT_VALUE(&buffer),
2528 GRN_TEXT_LEN(&buffer));
2529 if (!drilldown) {
2530 continue;
2531 }
2532
2533 drilldown->parsed_keys = data->drilldown.parsed_keys + i;
2534 drilldown->n_parsed_keys = 1;
2535
2536#define COPY(field) \
2537 drilldown->field = data->drilldown.field
2538
2539 COPY(sort_keys);
2540 COPY(output_columns);
2541 COPY(offset);
2542 COPY(limit);
2543 COPY(calc_types);
2544 COPY(calc_target_name);
2545 COPY(filter);
2546
2547#undef COPY
2548 }
2549 }
2550 }
2551
2552 if (!data->drilldowns) {
2553 return GRN_TRUE;
2554 }
2555
2556 if (!grn_select_drilldowns_execute(ctx, data)) {
2557 return GRN_FALSE;
2558 }
2559
2560 {
2561 unsigned int n_available_results = 0;
2562
2563 GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
2564 grn_drilldown_data *drilldown;
2565 grn_table_group_result *result;
2566
2567 grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
2568 result = &(drilldown->result);
2569 if (result->table) {
2570 n_available_results++;
2571 }
2572 } GRN_HASH_EACH_END(ctx, cursor);
2573
2574 if (data->drilldown.keys.length > 0) {
2575 data->output.n_elements += n_available_results;
2576 } else {
2577 if (n_available_results > 0) {
2578 data->output.n_elements += 1;
2579 }
2580 }
2581 }
2582
2583 return GRN_TRUE;
2584}
2585
2586static grn_bool
2587grn_select_output_drilldowns(grn_ctx *ctx,
2588 grn_select_data *data)
2589{
2590 grn_bool succeeded = GRN_TRUE;
2591 unsigned int n_available_results = 0;
2592 grn_bool is_labeled;
2593
2594 if (!data->drilldowns) {
2595 return GRN_TRUE;
2596 }
2597
2598 data->output.formatter->drilldowns_label(ctx, data);
2599
2600 GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
2601 grn_drilldown_data *drilldown;
2602 grn_table_group_result *result;
2603
2604 grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
2605 result = &(drilldown->result);
2606 if (result->table) {
2607 n_available_results++;
2608 }
2609 } GRN_HASH_EACH_END(ctx, cursor);
2610
2611 is_labeled = (data->drilldown.keys.length == 0);
2612
2613 data->output.formatter->drilldowns_open(ctx, data, n_available_results);
2614
2615 GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
2616 grn_drilldown_data *drilldown;
2617 grn_table_group_result *result;
2618 grn_obj *target_table;
2619 uint32_t n_hits;
2620 int offset;
2621 int limit;
2622
2623 grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
2624 result = &(drilldown->result);
2625
2626 if (!result->table) {
2627 continue;
2628 }
2629
2630 if (drilldown->filtered_result) {
2631 target_table = drilldown->filtered_result;
2632 } else {
2633 target_table = result->table;
2634 }
2635
2636 n_hits = grn_table_size(ctx, target_table);
2637
2638 offset = drilldown->offset;
2639 limit = drilldown->limit;
2640 grn_normalize_offset_and_limit(ctx, n_hits, &offset, &limit);
2641
2642 if (drilldown->sort_keys.length > 0) {
2643 grn_table_sort_key *sort_keys;
2644 uint32_t n_sort_keys;
2645 sort_keys = grn_table_sort_key_from_str(ctx,
2646 drilldown->sort_keys.value,
2647 drilldown->sort_keys.length,
2648 target_table, &n_sort_keys);
2649 if (sort_keys) {
2650 grn_obj *sorted;
2651 sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY,
2652 NULL, target_table);
2653 if (sorted) {
2654 grn_table_sort(ctx, target_table, offset, limit,
2655 sorted, sort_keys, n_sort_keys);
2656 data->output.formatter->drilldown_label(ctx, data, drilldown);
2657 if (!grn_proc_select_output_columns(ctx,
2658 sorted,
2659 n_hits,
2660 0,
2661 limit,
2662 drilldown->output_columns.value,
2663 drilldown->output_columns.length,
2664 data->filter.condition.expression)) {
2665 succeeded = GRN_FALSE;
2666 }
2667 grn_obj_unlink(ctx, sorted);
2668 }
2669 grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
2670 } else {
2671 succeeded = GRN_FALSE;
2672 }
2673 } else {
2674 data->output.formatter->drilldown_label(ctx, data, drilldown);
2675 if (!grn_proc_select_output_columns(ctx,
2676 target_table,
2677 n_hits,
2678 offset,
2679 limit,
2680 drilldown->output_columns.value,
2681 drilldown->output_columns.length,
2682 data->filter.condition.expression)) {
2683 succeeded = GRN_FALSE;
2684 }
2685 }
2686
2687 if (!succeeded) {
2688 break;
2689 }
2690
2691 if (is_labeled) {
2692 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
2693 ":", "output.drilldowns[%.*s](%d)",
2694 (int)(drilldown->label.length),
2695 drilldown->label.value,
2696 n_hits);
2697 } else {
2698 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
2699 ":", "output.drilldown(%d)", n_hits);
2700 }
2701 } GRN_HASH_EACH_END(ctx, cursor);
2702
2703 data->output.formatter->drilldowns_close(ctx, data);
2704
2705 return succeeded;
2706}
2707
2708static grn_bool
2709grn_select_output(grn_ctx *ctx, grn_select_data *data)
2710{
2711 grn_bool succeeded = GRN_TRUE;
2712
2713 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
2714 GRN_OUTPUT_ARRAY_OPEN("RESULT", data->output.n_elements);
2715 succeeded = grn_select_output_match(ctx, data);
2716 if (succeeded) {
2717 succeeded = grn_select_output_slices(ctx, data);
2718 }
2719 if (succeeded) {
2720 succeeded = grn_select_output_drilldowns(ctx, data);
2721 }
2722 GRN_OUTPUT_ARRAY_CLOSE();
2723 } else {
2724 grn_obj_format format;
2725 uint32_t n_additional_elements = 0;
2726
2727 if (data->slices) {
2728 n_additional_elements++;
2729 }
2730 if (data->drilldowns) {
2731 n_additional_elements++;
2732 }
2733
2734 succeeded = grn_select_output_match_open(ctx,
2735 data,
2736 &format,
2737 n_additional_elements);
2738 if (succeeded) {
2739 succeeded = grn_select_output_slices(ctx, data);
2740 if (succeeded) {
2741 succeeded = grn_select_output_drilldowns(ctx, data);
2742 }
2743 if (!grn_select_output_match_close(ctx, data, &format)) {
2744 succeeded = GRN_FALSE;
2745 }
2746 }
2747 }
2748
2749 return succeeded;
2750}
2751
2752static void
2753grn_select_output_slices_label_v1(grn_ctx *ctx, grn_select_data *data)
2754{
2755}
2756
2757static void
2758grn_select_output_slices_open_v1(grn_ctx *ctx,
2759 grn_select_data *data,
2760 unsigned int n_result_sets)
2761{
2762 GRN_OUTPUT_MAP_OPEN("SLICES", n_result_sets);
2763}
2764
2765static void
2766grn_select_output_slices_close_v1(grn_ctx *ctx, grn_select_data *data)
2767{
2768 GRN_OUTPUT_MAP_CLOSE();
2769}
2770
2771static void
2772grn_select_output_slice_label_v1(grn_ctx *ctx,
2773 grn_select_data *data,
2774 grn_slice_data *slice)
2775{
2776 GRN_OUTPUT_STR(slice->label.value, slice->label.length);
2777}
2778
2779static void
2780grn_select_output_drilldowns_label_v1(grn_ctx *ctx, grn_select_data *data)
2781{
2782}
2783
2784static void
2785grn_select_output_drilldowns_open_v1(grn_ctx *ctx,
2786 grn_select_data *data,
2787 unsigned int n_result_sets)
2788{
2789 if (data->drilldown.keys.length == 0) {
2790 GRN_OUTPUT_MAP_OPEN("DRILLDOWNS", n_result_sets);
2791 }
2792}
2793
2794static void
2795grn_select_output_drilldowns_close_v1(grn_ctx *ctx, grn_select_data *data)
2796{
2797 if (data->drilldown.keys.length == 0) {
2798 GRN_OUTPUT_MAP_CLOSE();
2799 }
2800}
2801
2802static void
2803grn_select_output_drilldown_label_v1(grn_ctx *ctx,
2804 grn_select_data *data,
2805 grn_drilldown_data *drilldown)
2806{
2807 if (data->drilldown.keys.length == 0) {
2808 GRN_OUTPUT_STR(drilldown->label.value, drilldown->label.length);
2809 }
2810}
2811
2812static grn_select_output_formatter grn_select_output_formatter_v1 = {
2813 grn_select_output_slices_label_v1,
2814 grn_select_output_slices_open_v1,
2815 grn_select_output_slices_close_v1,
2816 grn_select_output_slice_label_v1,
2817 grn_select_output_drilldowns_label_v1,
2818 grn_select_output_drilldowns_open_v1,
2819 grn_select_output_drilldowns_close_v1,
2820 grn_select_output_drilldown_label_v1
2821};
2822
2823static void
2824grn_select_output_slices_label_v3(grn_ctx *ctx, grn_select_data *data)
2825{
2826 GRN_OUTPUT_CSTR("slices");
2827}
2828
2829static void
2830grn_select_output_slices_open_v3(grn_ctx *ctx,
2831 grn_select_data *data,
2832 unsigned int n_result_sets)
2833{
2834 GRN_OUTPUT_MAP_OPEN("slices", n_result_sets);
2835}
2836
2837static void
2838grn_select_output_slices_close_v3(grn_ctx *ctx, grn_select_data *data)
2839{
2840 GRN_OUTPUT_MAP_CLOSE();
2841}
2842
2843static void
2844grn_select_output_slice_label_v3(grn_ctx *ctx,
2845 grn_select_data *data,
2846 grn_slice_data *slice)
2847{
2848 GRN_OUTPUT_STR(slice->label.value, slice->label.length);
2849}
2850
2851static void
2852grn_select_output_drilldowns_label_v3(grn_ctx *ctx, grn_select_data *data)
2853{
2854 GRN_OUTPUT_CSTR("drilldowns");
2855}
2856
2857static void
2858grn_select_output_drilldowns_open_v3(grn_ctx *ctx,
2859 grn_select_data *data,
2860 unsigned int n_result_sets)
2861{
2862 GRN_OUTPUT_MAP_OPEN("drilldowns", n_result_sets);
2863}
2864
2865static void
2866grn_select_output_drilldowns_close_v3(grn_ctx *ctx, grn_select_data *data)
2867{
2868 GRN_OUTPUT_MAP_CLOSE();
2869}
2870
2871static void
2872grn_select_output_drilldown_label_v3(grn_ctx *ctx,
2873 grn_select_data *data,
2874 grn_drilldown_data *drilldown)
2875{
2876 if (data->drilldown.keys.length == 0) {
2877 GRN_OUTPUT_STR(drilldown->label.value, drilldown->label.length);
2878 } else {
2879 grn_obj *key;
2880 char name[GRN_TABLE_MAX_KEY_SIZE];
2881 int name_len;
2882
2883 key = drilldown->parsed_keys[0].key;
2884 switch (key->header.type) {
2885 case GRN_COLUMN_FIX_SIZE :
2886 case GRN_COLUMN_VAR_SIZE :
2887 case GRN_COLUMN_INDEX :
2888 name_len = grn_column_name(ctx, key, name, GRN_TABLE_MAX_KEY_SIZE);
2889 break;
2890 default :
2891 name_len = grn_obj_name(ctx, key, name, GRN_TABLE_MAX_KEY_SIZE);
2892 break;
2893 }
2894 GRN_OUTPUT_STR(name, name_len);
2895 }
2896}
2897
2898static grn_select_output_formatter grn_select_output_formatter_v3 = {
2899 grn_select_output_slices_label_v3,
2900 grn_select_output_slices_open_v3,
2901 grn_select_output_slices_close_v3,
2902 grn_select_output_slice_label_v3,
2903 grn_select_output_drilldowns_label_v3,
2904 grn_select_output_drilldowns_open_v3,
2905 grn_select_output_drilldowns_close_v3,
2906 grn_select_output_drilldown_label_v3
2907};
2908
2909static grn_rc
2910grn_select(grn_ctx *ctx, grn_select_data *data)
2911{
2912 uint32_t nhits;
2913 grn_obj *outbuf = ctx->impl->output.buf;
2914 grn_content_type output_type = ctx->impl->output.type;
2915 char cache_key[GRN_CACHE_MAX_KEY_SIZE];
2916 uint32_t cache_key_size;
2917 long long int threshold, original_threshold = 0;
2918 grn_cache *cache_obj = grn_cache_current_get(ctx);
2919
2920 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
2921 data->output.formatter = &grn_select_output_formatter_v1;
2922 } else {
2923 data->output.formatter = &grn_select_output_formatter_v3;
2924 }
2925
2926 data->cacheable = 1;
2927 data->taintable = 0;
2928
2929 data->output.n_elements = 0;
2930
2931 grn_raw_string_lstrip(ctx, &(data->filter.query));
2932
2933 cache_key_size =
2934 data->table.length + 1 +
2935 data->filter.match_columns.length + 1 +
2936 data->filter.query.length + 1 +
2937 data->filter.filter.length + 1 +
2938 data->scorer.length + 1 +
2939 data->sort_keys.length + 1 +
2940 data->output_columns.length + 1 +
2941 data->match_escalation_threshold.length + 1 +
2942 data->filter.query_expander.length + 1 +
2943 data->filter.query_flags.length + 1 +
2944 data->adjuster.length + 1 +
2945 sizeof(grn_content_type) +
2946 sizeof(int) * 2 +
2947 sizeof(grn_command_version) +
2948 sizeof(grn_bool);
2949 if (data->slices) {
2950 GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
2951 grn_slice_data *slice;
2952 grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
2953 grn_raw_string_lstrip(ctx, &(slice->filter.query));
2954 cache_key_size +=
2955 slice->filter.match_columns.length + 1 +
2956 slice->filter.query.length + 1 +
2957 slice->filter.query_expander.length + 1 +
2958 slice->filter.query_flags.length + 1 +
2959 slice->filter.filter.length + 1 +
2960 slice->sort_keys.length + 1 +
2961 slice->output_columns.length + 1 +
2962 slice->label.length + 1 +
2963 sizeof(int) * 2;
2964 } GRN_HASH_EACH_END(ctx, cursor);
2965 }
2966#define DRILLDOWN_CACHE_SIZE(drilldown) \
2967 drilldown->keys.length + 1 + \
2968 drilldown->sort_keys.length + 1 + \
2969 drilldown->output_columns.length + 1 + \
2970 drilldown->label.length + 1 + \
2971 drilldown->calc_target_name.length + 1 + \
2972 drilldown->filter.length + 1 + \
2973 drilldown->table_name.length + 1 + \
2974 sizeof(int) * 2 + \
2975 sizeof(grn_table_group_flags)
2976 if (data->drilldown.keys.length > 0) {
2977 grn_drilldown_data *drilldown = &(data->drilldown);
2978 cache_key_size += DRILLDOWN_CACHE_SIZE(drilldown);
2979 }
2980 if (data->drilldowns) {
2981 GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
2982 grn_drilldown_data *drilldown;
2983 grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
2984 cache_key_size += DRILLDOWN_CACHE_SIZE(drilldown);
2985 } GRN_HASH_EACH_END(ctx, cursor);
2986 }
2987#undef DRILLDOWN_CACHE_SIZE
2988 if (cache_key_size <= GRN_CACHE_MAX_KEY_SIZE) {
2989 char *cp = cache_key;
2990
2991#define PUT_CACHE_KEY(string) \
2992 grn_memcpy(cp, (string).value, (string).length); \
2993 cp += (string).length; \
2994 *cp++ = '\0'
2995
2996 PUT_CACHE_KEY(data->table);
2997 PUT_CACHE_KEY(data->filter.match_columns);
2998 PUT_CACHE_KEY(data->filter.query);
2999 PUT_CACHE_KEY(data->filter.filter);
3000 PUT_CACHE_KEY(data->scorer);
3001 PUT_CACHE_KEY(data->sort_keys);
3002 PUT_CACHE_KEY(data->output_columns);
3003 if (data->slices) {
3004 GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
3005 grn_slice_data *slice;
3006 grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
3007 PUT_CACHE_KEY(slice->filter.match_columns);
3008 PUT_CACHE_KEY(slice->filter.query);
3009 PUT_CACHE_KEY(slice->filter.query_expander);
3010 PUT_CACHE_KEY(slice->filter.query_flags);
3011 PUT_CACHE_KEY(slice->filter.filter);
3012 PUT_CACHE_KEY(slice->sort_keys);
3013 PUT_CACHE_KEY(slice->output_columns);
3014 PUT_CACHE_KEY(slice->label);
3015 grn_memcpy(cp, &(slice->offset), sizeof(int));
3016 cp += sizeof(int);
3017 grn_memcpy(cp, &(slice->limit), sizeof(int));
3018 cp += sizeof(int);
3019 } GRN_HASH_EACH_END(ctx, cursor);
3020 }
3021#define PUT_CACHE_KEY_DRILLDOWN(drilldown) do { \
3022 PUT_CACHE_KEY(drilldown->keys); \
3023 PUT_CACHE_KEY(drilldown->sort_keys); \
3024 PUT_CACHE_KEY(drilldown->output_columns); \
3025 PUT_CACHE_KEY(drilldown->label); \
3026 PUT_CACHE_KEY(drilldown->calc_target_name); \
3027 PUT_CACHE_KEY(drilldown->filter); \
3028 PUT_CACHE_KEY(drilldown->table_name); \
3029 grn_memcpy(cp, &(drilldown->offset), sizeof(int)); \
3030 cp += sizeof(int); \
3031 grn_memcpy(cp, &(drilldown->limit), sizeof(int)); \
3032 cp += sizeof(int); \
3033 grn_memcpy(cp, \
3034 &(drilldown->calc_types), \
3035 sizeof(grn_table_group_flags)); \
3036 cp += sizeof(grn_table_group_flags); \
3037 } while (GRN_FALSE)
3038 if (data->drilldown.keys.length > 0) {
3039 grn_drilldown_data *drilldown = &(data->drilldown);
3040 PUT_CACHE_KEY_DRILLDOWN(drilldown);
3041 }
3042 if (data->drilldowns) {
3043 GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
3044 grn_drilldown_data *drilldown;
3045 grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
3046 PUT_CACHE_KEY_DRILLDOWN(drilldown);
3047 } GRN_HASH_EACH_END(ctx, cursor);
3048 }
3049#undef PUT_CACHE_KEY_DRILLDOWN
3050 PUT_CACHE_KEY(data->match_escalation_threshold);
3051 PUT_CACHE_KEY(data->filter.query_expander);
3052 PUT_CACHE_KEY(data->filter.query_flags);
3053 PUT_CACHE_KEY(data->adjuster);
3054 grn_memcpy(cp, &output_type, sizeof(grn_content_type));
3055 cp += sizeof(grn_content_type);
3056 grn_memcpy(cp, &(data->offset), sizeof(int));
3057 cp += sizeof(int);
3058 grn_memcpy(cp, &(data->limit), sizeof(int));
3059 cp += sizeof(int);
3060 grn_memcpy(cp, &(ctx->impl->command.version), sizeof(grn_command_version));
3061 cp += sizeof(grn_command_version);
3062 grn_memcpy(cp, &(ctx->impl->output.is_pretty), sizeof(grn_bool));
3063 cp += sizeof(grn_bool);
3064#undef PUT_CACHE_KEY
3065
3066 {
3067 grn_rc rc;
3068 rc = grn_cache_fetch(ctx, cache_obj, cache_key, cache_key_size, outbuf);
3069 if (rc == GRN_SUCCESS) {
3070 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_CACHE,
3071 ":", "cache(%" GRN_FMT_LLD ")",
3072 (long long int)GRN_TEXT_LEN(outbuf));
3073 return ctx->rc;
3074 }
3075 }
3076 }
3077 if (data->match_escalation_threshold.length) {
3078 const char *end, *rest;
3079 original_threshold = grn_ctx_get_match_escalation_threshold(ctx);
3080 end =
3081 data->match_escalation_threshold.value +
3082 data->match_escalation_threshold.length;
3083 threshold = grn_atoll(data->match_escalation_threshold.value, end, &rest);
3084 if (end == rest) {
3085 grn_ctx_set_match_escalation_threshold(ctx, threshold);
3086 }
3087 }
3088
3089 data->tables.target = grn_ctx_get(ctx, data->table.value, data->table.length);
3090 if (!data->tables.target) {
3091 GRN_PLUGIN_ERROR(ctx,
3092 GRN_INVALID_ARGUMENT,
3093 "[select][table] invalid name: <%.*s>",
3094 (int)(data->table.length),
3095 data->table.value);
3096 goto exit;
3097 }
3098
3099 {
3100 if (data->filter.filter.length > 0 &&
3101 (data->filter.filter.value[0] == '?') &&
3102 (ctx->impl->output.type == GRN_CONTENT_JSON)) {
3103 ctx->rc = grn_ts_select(ctx, data->tables.target,
3104 data->filter.filter.value + 1,
3105 data->filter.filter.length - 1,
3106 data->scorer.value,
3107 data->scorer.length,
3108 data->sort_keys.value,
3109 data->sort_keys.length,
3110 data->output_columns.value,
3111 data->output_columns.length,
3112 data->offset,
3113 data->limit);
3114 if (!ctx->rc &&
3115 data->cacheable > 0 &&
3116 cache_key_size <= GRN_CACHE_MAX_KEY_SIZE &&
3117 (!data->cache.value ||
3118 data->cache.length != 2 ||
3119 data->cache.value[0] != 'n' ||
3120 data->cache.value[1] != 'o')) {
3121 grn_cache_update(ctx, cache_obj, cache_key, cache_key_size, outbuf);
3122 }
3123 goto exit;
3124 }
3125
3126 data->tables.initial = data->tables.target;
3127 if (!grn_select_apply_initial_columns(ctx, data)) {
3128 goto exit;
3129 }
3130
3131 if (!grn_select_filter(ctx, data)) {
3132 goto exit;
3133 }
3134
3135 nhits = grn_table_size(ctx, data->tables.result);
3136 GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
3137 ":", "select(%d)", nhits);
3138
3139 if (!grn_select_apply_filtered_columns(ctx, data)) {
3140 goto exit;
3141 }
3142
3143 {
3144 grn_bool succeeded;
3145
3146 /* For select results */
3147 data->output.n_elements = 1;
3148
3149 if (!grn_select_apply_adjuster(ctx, data)) {
3150 goto exit;
3151 }
3152
3153 if (!grn_select_apply_scorer(ctx, data)) {
3154 goto exit;
3155 }
3156
3157 grn_normalize_offset_and_limit(ctx, nhits,
3158 &(data->offset), &(data->limit));
3159
3160 if (!grn_select_sort(ctx, data)) {
3161 goto exit;
3162 }
3163
3164 if (!grn_select_apply_output_columns(ctx, data)) {
3165 goto exit;
3166 }
3167
3168 if (!grn_select_prepare_slices(ctx, data)) {
3169 goto exit;
3170 }
3171
3172 if (!grn_select_prepare_drilldowns(ctx, data)) {
3173 goto exit;
3174 }
3175
3176 succeeded = grn_select_output(ctx, data);
3177 if (!succeeded) {
3178 goto exit;
3179 }
3180 }
3181 if (!ctx->rc &&
3182 data->cacheable &&
3183 cache_key_size <= GRN_CACHE_MAX_KEY_SIZE &&
3184 (!data->cache.value ||
3185 data->cache.length != 2 ||
3186 data->cache.value[0] != 'n' ||
3187 data->cache.value[1] != 'o')) {
3188 grn_cache_update(ctx, cache_obj, cache_key, cache_key_size, outbuf);
3189 }
3190 if (data->taintable > 0) {
3191 grn_db_touch(ctx, DB_OBJ(data->tables.target)->db);
3192 }
3193 }
3194
3195exit :
3196 if (data->match_escalation_threshold.length > 0) {
3197 grn_ctx_set_match_escalation_threshold(ctx, original_threshold);
3198 }
3199
3200 /* GRN_LOG(ctx, GRN_LOG_NONE, "%d", ctx->seqno); */
3201
3202 return ctx->rc;
3203}
3204
3205static grn_slice_data *
3206grn_select_data_slices_add(grn_ctx *ctx,
3207 grn_select_data *data,
3208 const char *label,
3209 size_t label_len)
3210{
3211 grn_slice_data *slice = NULL;
3212 int added;
3213
3214 if (!data->slices) {
3215 data->slices = grn_hash_create(ctx,
3216 NULL,
3217 GRN_TABLE_MAX_KEY_SIZE,
3218 sizeof(grn_slice_data),
3219 GRN_OBJ_TABLE_HASH_KEY |
3220 GRN_OBJ_KEY_VAR_SIZE |
3221 GRN_HASH_TINY);
3222 if (!data->slices) {
3223 GRN_PLUGIN_ERROR(ctx,
3224 GRN_INVALID_ARGUMENT,
3225 "[select][slices] "
3226 "failed to allocate slices data: %s",
3227 ctx->errbuf);
3228 return NULL;
3229 }
3230 }
3231
3232 grn_hash_add(ctx,
3233 data->slices,
3234 label,
3235 label_len,
3236 (void **)&slice,
3237 &added);
3238 if (added) {
3239 grn_slice_data_init(ctx, slice, label, label_len);
3240 }
3241
3242 return slice;
3243}
3244
3245static grn_bool
3246grn_select_data_fill_slice_labels(grn_ctx *ctx,
3247 grn_user_data *user_data,
3248 grn_select_data *data)
3249{
3250 grn_obj *vars;
3251 grn_table_cursor *cursor;
3252 const char *prefix = "slices[";
3253 int prefix_len;
3254
3255 vars = grn_plugin_proc_get_vars(ctx, user_data);
3256
3257 cursor = grn_table_cursor_open(ctx, vars, NULL, 0, NULL, 0, 0, -1, 0);
3258 if (!cursor) {
3259 return GRN_FALSE;
3260 }
3261
3262 prefix_len = strlen(prefix);
3263 while (grn_table_cursor_next(ctx, cursor)) {
3264 void *key;
3265 char *name;
3266 int name_len;
3267 name_len = grn_table_cursor_get_key(ctx, cursor, &key);
3268 name = key;
3269 if (name_len > prefix_len + 1 &&
3270 strncmp(prefix, name, prefix_len) == 0) {
3271 const char *label_end;
3272 size_t label_len;
3273 label_end = memchr(name + prefix_len + 1,
3274 ']',
3275 name_len - prefix_len - 1);
3276 if (!label_end) {
3277 continue;
3278 }
3279 label_len = (label_end - name) - prefix_len;
3280 grn_select_data_slices_add(ctx,
3281 data,
3282 name + prefix_len,
3283 label_len);
3284 }
3285 }
3286 grn_table_cursor_close(ctx, cursor);
3287
3288 return GRN_TRUE;
3289}
3290
3291static grn_bool
3292grn_select_data_fill_slices(grn_ctx *ctx,
3293 grn_user_data *user_data,
3294 grn_select_data *data)
3295{
3296 if (!grn_select_data_fill_slice_labels(ctx, user_data, data)) {
3297 return GRN_FALSE;
3298 }
3299
3300 GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
3301 grn_slice_data *slice;
3302 char slice_label[GRN_TABLE_MAX_KEY_SIZE];
3303 char key_name[GRN_TABLE_MAX_KEY_SIZE];
3304 grn_obj *match_columns;
3305 grn_obj *query;
3306 grn_obj *query_expander;
3307 grn_obj *query_flags;
3308 grn_obj *filter;
3309 grn_obj *sort_keys;
3310 grn_obj *output_columns;
3311 grn_obj *offset;
3312 grn_obj *limit;
3313
3314 grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
3315
3316 grn_snprintf(slice_label,
3317 GRN_TABLE_MAX_KEY_SIZE,
3318 GRN_TABLE_MAX_KEY_SIZE,
3319 "slices[%.*s].",
3320 (int)(slice->label.length),
3321 slice->label.value);
3322
3323#define GET_VAR(name) \
3324 grn_snprintf(key_name, \
3325 GRN_TABLE_MAX_KEY_SIZE, \
3326 GRN_TABLE_MAX_KEY_SIZE, \
3327 "%s%s", slice_label, #name); \
3328 name = grn_plugin_proc_get_var(ctx, user_data, key_name, -1);
3329
3330 GET_VAR(match_columns);
3331 GET_VAR(query);
3332 GET_VAR(query_expander);
3333 GET_VAR(query_flags);
3334 GET_VAR(filter);
3335 GET_VAR(sort_keys);
3336 GET_VAR(output_columns);
3337 GET_VAR(offset);
3338 GET_VAR(limit);
3339
3340#undef GET_VAR
3341
3342 grn_slice_data_fill(ctx,
3343 slice,
3344 match_columns,
3345 query,
3346 query_expander,
3347 query_flags,
3348 filter,
3349 sort_keys,
3350 output_columns,
3351 offset,
3352 limit);
3353 } GRN_HASH_EACH_END(ctx, cursor);
3354
3355 return GRN_TRUE;
3356}
3357
3358static grn_bool
3359grn_select_data_fill_drilldown_labels(grn_ctx *ctx,
3360 grn_user_data *user_data,
3361 grn_select_data *data,
3362 const char *prefix)
3363{
3364 grn_obj *vars;
3365 grn_table_cursor *cursor;
3366 int prefix_len;
3367
3368 vars = grn_plugin_proc_get_vars(ctx, user_data);
3369
3370 cursor = grn_table_cursor_open(ctx, vars, NULL, 0, NULL, 0, 0, -1, 0);
3371 if (!cursor) {
3372 return GRN_FALSE;
3373 }
3374
3375 prefix_len = strlen(prefix);
3376 while (grn_table_cursor_next(ctx, cursor)) {
3377 void *key;
3378 char *name;
3379 int name_len;
3380 name_len = grn_table_cursor_get_key(ctx, cursor, &key);
3381 name = key;
3382 if (name_len > prefix_len + 1 &&
3383 strncmp(prefix, name, prefix_len) == 0) {
3384 const char *label_end;
3385 size_t label_len;
3386 label_end = memchr(name + prefix_len + 1,
3387 ']',
3388 name_len - prefix_len - 1);
3389 if (!label_end) {
3390 continue;
3391 }
3392 label_len = (label_end - name) - prefix_len;
3393 grn_select_data_drilldowns_add(ctx,
3394 data,
3395 name + prefix_len,
3396 label_len);
3397 }
3398 }
3399 grn_table_cursor_close(ctx, cursor);
3400
3401 return GRN_TRUE;
3402}
3403
3404static grn_bool
3405grn_select_data_fill_drilldown_columns(grn_ctx *ctx,
3406 grn_user_data *user_data,
3407 grn_drilldown_data *drilldown,
3408 const char *parameter_key)
3409{
3410 char prefix[GRN_TABLE_MAX_KEY_SIZE];
3411
3412 grn_snprintf(prefix,
3413 GRN_TABLE_MAX_KEY_SIZE,
3414 GRN_TABLE_MAX_KEY_SIZE,
3415 "%s[%.*s].",
3416 parameter_key,
3417 (int)(drilldown->label.length),
3418 drilldown->label.value);
3419 return grn_columns_fill(ctx,
3420 user_data,
3421 &(drilldown->columns),
3422 prefix,
3423 strlen(prefix));
3424}
3425
3426static grn_bool
3427grn_select_data_fill_drilldowns(grn_ctx *ctx,
3428 grn_user_data *user_data,
3429 grn_select_data *data)
3430{
3431 grn_obj *drilldown;
3432
3433 drilldown = grn_plugin_proc_get_var(ctx, user_data, "drilldown", -1);
3434 if (GRN_TEXT_LEN(drilldown) > 0) {
3435 grn_obj *sort_keys;
3436
3437 sort_keys = grn_plugin_proc_get_var(ctx, user_data,
3438 "drilldown_sort_keys", -1);
3439 if (GRN_TEXT_LEN(sort_keys) == 0) {
3440 /* For backward compatibility */
3441 sort_keys = grn_plugin_proc_get_var(ctx, user_data,
3442 "drilldown_sortby", -1);
3443 }
3444 grn_drilldown_data_fill(ctx,
3445 &(data->drilldown),
3446 drilldown,
3447 sort_keys,
3448 grn_plugin_proc_get_var(ctx, user_data,
3449 "drilldown_output_columns",
3450 -1),
3451 grn_plugin_proc_get_var(ctx, user_data,
3452 "drilldown_offset", -1),
3453 grn_plugin_proc_get_var(ctx, user_data,
3454 "drilldown_limit", -1),
3455 grn_plugin_proc_get_var(ctx, user_data,
3456 "drilldown_calc_types", -1),
3457 grn_plugin_proc_get_var(ctx, user_data,
3458 "drilldown_calc_target", -1),
3459 grn_plugin_proc_get_var(ctx, user_data,
3460 "drilldown_filter", -1),
3461 NULL);
3462 return GRN_TRUE;
3463 } else {
3464 grn_bool succeeded = GRN_TRUE;
3465
3466 if (!grn_select_data_fill_drilldown_labels(ctx, user_data, data,
3467 "drilldowns[")) {
3468 return GRN_FALSE;
3469 }
3470
3471 /* For backward compatibility */
3472 if (!grn_select_data_fill_drilldown_labels(ctx, user_data, data,
3473 "drilldown[")) {
3474 return GRN_FALSE;
3475 }
3476
3477 GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
3478 grn_drilldown_data *drilldown;
3479 grn_obj *keys = NULL;
3480 grn_obj *sort_keys = NULL;
3481 grn_obj *output_columns = NULL;
3482 grn_obj *offset = NULL;
3483 grn_obj *limit = NULL;
3484 grn_obj *calc_types = NULL;
3485 grn_obj *calc_target = NULL;
3486 grn_obj *filter = NULL;
3487 grn_obj *table = NULL;
3488
3489 grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
3490
3491 succeeded = grn_select_data_fill_drilldown_columns(ctx,
3492 user_data,
3493 drilldown,
3494 "drilldowns");
3495 if (!succeeded) {
3496 break;
3497 }
3498
3499 /* For backward compatibility */
3500 succeeded = grn_select_data_fill_drilldown_columns(ctx,
3501 user_data,
3502 drilldown,
3503 "drilldown");
3504 if (!succeeded) {
3505 break;
3506 }
3507
3508#define GET_VAR_RAW(parameter_key, name) do { \
3509 if (!name) { \
3510 char key_name[GRN_TABLE_MAX_KEY_SIZE]; \
3511 grn_snprintf(key_name, \
3512 GRN_TABLE_MAX_KEY_SIZE, \
3513 GRN_TABLE_MAX_KEY_SIZE, \
3514 "%s[%.*s].%s", \
3515 (parameter_key), \
3516 (int)(drilldown->label.length), \
3517 drilldown->label.value, \
3518 #name); \
3519 name = grn_plugin_proc_get_var(ctx, user_data, key_name, -1); \
3520 } \
3521 } while (GRN_FALSE)
3522
3523#define GET_VAR(name) do { \
3524 GET_VAR_RAW("drilldowns", name); \
3525 /* For backward compatibility */ \
3526 GET_VAR_RAW("drilldown", name); \
3527 } while (GRN_FALSE)
3528
3529 GET_VAR(keys);
3530 GET_VAR(sort_keys);
3531 if (!sort_keys) {
3532 grn_obj *sortby = NULL;
3533 GET_VAR(sortby);
3534 sort_keys = sortby;
3535 }
3536 GET_VAR(output_columns);
3537 GET_VAR(offset);
3538 GET_VAR(limit);
3539 GET_VAR(calc_types);
3540 GET_VAR(calc_target);
3541 GET_VAR(filter);
3542 GET_VAR(table);
3543
3544#undef GET_VAR
3545
3546#undef GET_VAR_RAW
3547
3548 grn_drilldown_data_fill(ctx,
3549 drilldown,
3550 keys,
3551 sort_keys,
3552 output_columns,
3553 offset,
3554 limit,
3555 calc_types,
3556 calc_target,
3557 filter,
3558 table);
3559 } GRN_HASH_EACH_END(ctx, cursor);
3560
3561 return succeeded;
3562 }
3563}
3564
3565static grn_obj *
3566command_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3567{
3568 grn_select_data data;
3569
3570 grn_columns_init(ctx, &(data.columns));
3571 grn_filter_data_init(ctx, &(data.filter));
3572
3573 data.tables.target = NULL;
3574 data.tables.initial = NULL;
3575 data.tables.result = NULL;
3576 data.tables.sorted = NULL;
3577
3578 data.slices = NULL;
3579 grn_drilldown_data_init(ctx, &(data.drilldown), NULL, 0);
3580 data.drilldowns = NULL;
3581
3582 data.table.value = grn_plugin_proc_get_var_string(ctx, user_data,
3583 "table", -1,
3584 &(data.table.length));
3585#define GET_VAR(name) \
3586 grn_plugin_proc_get_var(ctx, user_data, name, strlen(name))
3587
3588 {
3589 grn_obj *query_expander;
3590
3591 query_expander = GET_VAR("query_expander");
3592 if (GRN_TEXT_LEN(query_expander) == 0) {
3593 query_expander = GET_VAR("query_expansion");
3594 }
3595
3596 grn_filter_data_fill(ctx,
3597 &(data.filter),
3598 GET_VAR("match_columns"),
3599 GET_VAR("query"),
3600 query_expander,
3601 GET_VAR("query_flags"),
3602 GET_VAR("filter"));
3603 }
3604#undef GET_VAR
3605
3606 data.scorer.value =
3607 grn_plugin_proc_get_var_string(ctx, user_data,
3608 "scorer", -1,
3609 &(data.scorer.length));
3610 data.sort_keys.value =
3611 grn_plugin_proc_get_var_string(ctx, user_data,
3612 "sort_keys", -1,
3613 &(data.sort_keys.length));
3614 if (data.sort_keys.length == 0) {
3615 /* For backward compatibility */
3616 data.sort_keys.value =
3617 grn_plugin_proc_get_var_string(ctx, user_data,
3618 "sortby", -1,
3619 &(data.sort_keys.length));
3620 }
3621 data.output_columns.value =
3622 grn_plugin_proc_get_var_string(ctx, user_data,
3623 "output_columns", -1,
3624 &(data.output_columns.length));
3625 if (!data.output_columns.value) {
3626 data.output_columns.value = GRN_SELECT_DEFAULT_OUTPUT_COLUMNS;
3627 data.output_columns.length = strlen(GRN_SELECT_DEFAULT_OUTPUT_COLUMNS);
3628 }
3629 data.offset = grn_plugin_proc_get_var_int32(ctx, user_data,
3630 "offset", -1,
3631 0);
3632 data.limit = grn_plugin_proc_get_var_int32(ctx, user_data,
3633 "limit", -1,
3634 GRN_SELECT_DEFAULT_LIMIT);
3635
3636 data.cache.value = grn_plugin_proc_get_var_string(ctx, user_data,
3637 "cache", -1,
3638 &(data.cache.length));
3639 data.match_escalation_threshold.value =
3640 grn_plugin_proc_get_var_string(ctx, user_data,
3641 "match_escalation_threshold", -1,
3642 &(data.match_escalation_threshold.length));
3643
3644 data.adjuster.value =
3645 grn_plugin_proc_get_var_string(ctx, user_data,
3646 "adjuster", -1,
3647 &(data.adjuster.length));
3648
3649 if (!grn_select_data_fill_slices(ctx, user_data, &data)) {
3650 goto exit;
3651 }
3652
3653 if (!grn_select_data_fill_drilldowns(ctx, user_data, &data)) {
3654 goto exit;
3655 }
3656
3657 if (!grn_columns_fill(ctx, user_data, &(data.columns), NULL, 0)) {
3658 goto exit;
3659 }
3660
3661 grn_select(ctx, &data);
3662
3663exit :
3664 if (data.drilldowns) {
3665 GRN_HASH_EACH_BEGIN(ctx, data.drilldowns, cursor, id) {
3666 grn_drilldown_data *drilldown;
3667 grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
3668 grn_drilldown_data_fin(ctx, drilldown);
3669 } GRN_HASH_EACH_END(ctx, cursor);
3670 grn_hash_close(ctx, data.drilldowns);
3671 }
3672
3673 if (data.drilldown.parsed_keys) {
3674 grn_table_sort_key_close(ctx,
3675 data.drilldown.parsed_keys,
3676 data.drilldown.n_parsed_keys);
3677 }
3678 grn_drilldown_data_fin(ctx, &(data.drilldown));
3679
3680 if (data.slices) {
3681 GRN_HASH_EACH_BEGIN(ctx, data.slices, cursor, id) {
3682 grn_slice_data *slice;
3683 grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
3684 grn_slice_data_fin(ctx, slice);
3685 } GRN_HASH_EACH_END(ctx, cursor);
3686 grn_hash_close(ctx, data.slices);
3687 }
3688
3689 if (data.tables.sorted) {
3690 grn_obj_unlink(ctx, data.tables.sorted);
3691 }
3692
3693 if (data.tables.result == data.filter.filtered) {
3694 data.tables.result = NULL;
3695 }
3696 grn_filter_data_fin(ctx, &(data.filter));
3697
3698 if (data.tables.result &&
3699 data.tables.result != data.tables.initial &&
3700 data.tables.result != data.tables.target) {
3701 grn_obj_unlink(ctx, data.tables.result);
3702 }
3703
3704 if (data.tables.initial && data.tables.initial != data.tables.target) {
3705 grn_obj_unlink(ctx, data.tables.initial);
3706 }
3707
3708 if (data.tables.target) {
3709 grn_obj_unlink(ctx, data.tables.target);
3710 }
3711
3712 grn_columns_fin(ctx, &(data.columns));
3713
3714 return NULL;
3715}
3716
3717#define N_VARS 26
3718#define DEFINE_VARS grn_expr_var vars[N_VARS]
3719
3720static void
3721init_vars(grn_ctx *ctx, grn_expr_var *vars)
3722{
3723 grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
3724 grn_plugin_expr_var_init(ctx, &(vars[1]), "table", -1);
3725 grn_plugin_expr_var_init(ctx, &(vars[2]), "match_columns", -1);
3726 grn_plugin_expr_var_init(ctx, &(vars[3]), "query", -1);
3727 grn_plugin_expr_var_init(ctx, &(vars[4]), "filter", -1);
3728 grn_plugin_expr_var_init(ctx, &(vars[5]), "scorer", -1);
3729 /* Deprecated since 6.0.3. Use sort_keys instead. */
3730 grn_plugin_expr_var_init(ctx, &(vars[6]), "sortby", -1);
3731 grn_plugin_expr_var_init(ctx, &(vars[7]), "output_columns", -1);
3732 grn_plugin_expr_var_init(ctx, &(vars[8]), "offset", -1);
3733 grn_plugin_expr_var_init(ctx, &(vars[9]), "limit", -1);
3734 grn_plugin_expr_var_init(ctx, &(vars[10]), "drilldown", -1);
3735 /* Deprecated since 6.0.3. Use drilldown_sort_keys instead. */
3736 grn_plugin_expr_var_init(ctx, &(vars[11]), "drilldown_sortby", -1);
3737 grn_plugin_expr_var_init(ctx, &(vars[12]), "drilldown_output_columns", -1);
3738 grn_plugin_expr_var_init(ctx, &(vars[13]), "drilldown_offset", -1);
3739 grn_plugin_expr_var_init(ctx, &(vars[14]), "drilldown_limit", -1);
3740 grn_plugin_expr_var_init(ctx, &(vars[15]), "cache", -1);
3741 grn_plugin_expr_var_init(ctx, &(vars[16]), "match_escalation_threshold", -1);
3742 /* Deprecated. Use query_expander instead. */
3743 grn_plugin_expr_var_init(ctx, &(vars[17]), "query_expansion", -1);
3744 grn_plugin_expr_var_init(ctx, &(vars[18]), "query_flags", -1);
3745 grn_plugin_expr_var_init(ctx, &(vars[19]), "query_expander", -1);
3746 grn_plugin_expr_var_init(ctx, &(vars[20]), "adjuster", -1);
3747 grn_plugin_expr_var_init(ctx, &(vars[21]), "drilldown_calc_types", -1);
3748 grn_plugin_expr_var_init(ctx, &(vars[22]), "drilldown_calc_target", -1);
3749 grn_plugin_expr_var_init(ctx, &(vars[23]), "drilldown_filter", -1);
3750 grn_plugin_expr_var_init(ctx, &(vars[24]), "sort_keys", -1);
3751 grn_plugin_expr_var_init(ctx, &(vars[25]), "drilldown_sort_keys", -1);
3752}
3753
3754void
3755grn_proc_init_select(grn_ctx *ctx)
3756{
3757 DEFINE_VARS;
3758
3759 init_vars(ctx, vars);
3760 grn_plugin_command_create(ctx,
3761 "select", -1,
3762 command_select,
3763 N_VARS - 1,
3764 vars + 1);
3765}
3766
3767static grn_obj *
3768command_define_selector(grn_ctx *ctx, int nargs, grn_obj **args,
3769 grn_user_data *user_data)
3770{
3771 uint32_t i, nvars;
3772 grn_expr_var *vars;
3773
3774 grn_proc_get_info(ctx, user_data, &vars, &nvars, NULL);
3775 for (i = 1; i < nvars; i++) {
3776 grn_obj *var;
3777 var = grn_plugin_proc_get_var_by_offset(ctx, user_data, i);
3778 GRN_TEXT_SET(ctx, &((vars + i)->value),
3779 GRN_TEXT_VALUE(var),
3780 GRN_TEXT_LEN(var));
3781 }
3782 {
3783 grn_obj *name;
3784 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
3785 grn_plugin_command_create(ctx,
3786 GRN_TEXT_VALUE(name),
3787 GRN_TEXT_LEN(name),
3788 command_select,
3789 nvars - 1,
3790 vars + 1);
3791 }
3792 GRN_OUTPUT_BOOL(!ctx->rc);
3793
3794 return NULL;
3795}
3796
3797void
3798grn_proc_init_define_selector(grn_ctx *ctx)
3799{
3800 DEFINE_VARS;
3801
3802 init_vars(ctx, vars);
3803 grn_plugin_command_create(ctx,
3804 "define_selector", -1,
3805 command_define_selector,
3806 N_VARS,
3807 vars);
3808}
3809