1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2010-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-1335  USA
17 */
18 #include "grn.h"
19 #include "grn_db.h"
20 #include "grn_ctx_impl.h"
21 #include "grn_ctx_impl_mrb.h"
22 #include <string.h>
23 #include "grn_ii.h"
24 #include "grn_geo.h"
25 #include "grn_expr.h"
26 #include "grn_expr_code.h"
27 #include "grn_expr_executor.h"
28 #include "grn_scanner.h"
29 #include "grn_util.h"
30 #include "grn_report.h"
31 #include "grn_token_cursor.h"
32 #include "grn_mrb.h"
33 #include "mrb/mrb_expr.h"
34 
35 #ifdef GRN_WITH_ONIGMO
36 # define GRN_SUPPORT_REGEXP
37 #endif
38 
39 #ifdef GRN_SUPPORT_REGEXP
40 # include "grn_normalizer.h"
41 # include <onigmo.h>
42 #endif
43 
44 static double grn_table_select_enough_filtered_ratio = 0.0;
45 static int grn_table_select_max_n_enough_filtered_records = 1000;
46 static grn_bool grn_table_select_and_min_skip_enable = GRN_TRUE;
47 static grn_bool grn_scan_info_regexp_dot_asterisk_enable = GRN_TRUE;
48 
49 void
grn_expr_init_from_env(void)50 grn_expr_init_from_env(void)
51 {
52   {
53     char grn_table_select_enough_filtered_ratio_env[GRN_ENV_BUFFER_SIZE];
54     grn_getenv("GRN_TABLE_SELECT_ENOUGH_FILTERED_RATIO",
55                grn_table_select_enough_filtered_ratio_env,
56                GRN_ENV_BUFFER_SIZE);
57     if (grn_table_select_enough_filtered_ratio_env[0]) {
58       grn_table_select_enough_filtered_ratio =
59         atof(grn_table_select_enough_filtered_ratio_env);
60     }
61   }
62 
63   {
64     char grn_table_select_max_n_enough_filtered_records_env[GRN_ENV_BUFFER_SIZE];
65     grn_getenv("GRN_TABLE_SELECT_MAX_N_ENOUGH_FILTERED_RECORDS",
66                grn_table_select_max_n_enough_filtered_records_env,
67                GRN_ENV_BUFFER_SIZE);
68     if (grn_table_select_max_n_enough_filtered_records_env[0]) {
69       grn_table_select_max_n_enough_filtered_records =
70         atoi(grn_table_select_max_n_enough_filtered_records_env);
71     }
72   }
73 
74   {
75     char grn_table_select_and_min_skip_enable_env[GRN_ENV_BUFFER_SIZE];
76     grn_getenv("GRN_TABLE_SELECT_AND_MIN_SKIP_ENABLE",
77                grn_table_select_and_min_skip_enable_env,
78                GRN_ENV_BUFFER_SIZE);
79     if (strcmp(grn_table_select_and_min_skip_enable_env, "no") == 0) {
80       grn_table_select_and_min_skip_enable = GRN_FALSE;
81     } else {
82       grn_table_select_and_min_skip_enable = GRN_TRUE;
83     }
84   }
85 
86   {
87     char grn_scan_info_regexp_dot_asterisk_enable_env[GRN_ENV_BUFFER_SIZE];
88     grn_getenv("GRN_SCAN_INFO_REGEXP_DOT_ASTERISK_ENABLE",
89                grn_scan_info_regexp_dot_asterisk_enable_env,
90                GRN_ENV_BUFFER_SIZE);
91     if (strcmp(grn_scan_info_regexp_dot_asterisk_enable_env, "no") == 0) {
92       grn_scan_info_regexp_dot_asterisk_enable = GRN_FALSE;
93     } else {
94       grn_scan_info_regexp_dot_asterisk_enable = GRN_TRUE;
95     }
96   }
97 }
98 
99 grn_obj *
grn_expr_alloc(grn_ctx * ctx,grn_obj * expr,grn_id domain,unsigned char flags)100 grn_expr_alloc(grn_ctx *ctx, grn_obj *expr, grn_id domain, unsigned char flags)
101 {
102   grn_obj *res = NULL;
103   grn_expr *e = (grn_expr *)expr;
104   if (e) {
105     if (e->values_curr >= e->values_size) {
106       // todo : expand values.
107       ERR(GRN_NO_MEMORY_AVAILABLE, "no more e->values");
108       return NULL;
109     }
110     res = &e->values[e->values_curr++];
111     if (e->values_curr > e->values_tail) { e->values_tail = e->values_curr; }
112     grn_obj_reinit(ctx, res, domain, flags);
113   }
114   return res;
115 }
116 
117 grn_hash *
grn_expr_get_vars(grn_ctx * ctx,grn_obj * expr,unsigned int * nvars)118 grn_expr_get_vars(grn_ctx *ctx, grn_obj *expr, unsigned int *nvars)
119 {
120   grn_hash *vars = NULL;
121   if (expr->header.type == GRN_PROC || expr->header.type == GRN_EXPR) {
122     grn_id id = DB_OBJ(expr)->id;
123     grn_expr *e = (grn_expr *)expr;
124     int added = 0;
125     grn_hash **vp;
126     if (grn_hash_add(ctx, ctx->impl->expr_vars, &id, sizeof(grn_id), (void **)&vp, &added)) {
127       if (!*vp) {
128         *vp = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, sizeof(grn_obj),
129                               GRN_OBJ_KEY_VAR_SIZE|GRN_OBJ_TEMPORARY|GRN_HASH_TINY);
130         if (*vp) {
131           uint32_t i;
132           grn_obj *value;
133           grn_expr_var *v;
134           for (v = e->vars, i = e->nvars; i; v++, i--) {
135             grn_hash_add(ctx, *vp, v->name, v->name_size, (void **)&value, &added);
136             GRN_OBJ_INIT(value, v->value.header.type, 0, v->value.header.domain);
137             GRN_TEXT_PUT(ctx, value, GRN_TEXT_VALUE(&v->value), GRN_TEXT_LEN(&v->value));
138           }
139         }
140       }
141       vars = *vp;
142     }
143   }
144   *nvars = vars ? GRN_HASH_SIZE(vars) : 0;
145   return vars;
146 }
147 
148 grn_rc
grn_expr_clear_vars(grn_ctx * ctx,grn_obj * expr)149 grn_expr_clear_vars(grn_ctx *ctx, grn_obj *expr)
150 {
151   if (expr->header.type == GRN_PROC || expr->header.type == GRN_EXPR) {
152     grn_hash **vp;
153     grn_id eid, id = DB_OBJ(expr)->id;
154     if ((eid = grn_hash_get(ctx, ctx->impl->expr_vars, &id, sizeof(grn_id), (void **)&vp))) {
155       if (*vp) {
156         grn_obj *value;
157         GRN_HASH_EACH(ctx, *vp, i, NULL, NULL, (void **)&value, {
158           GRN_OBJ_FIN(ctx, value);
159         });
160         grn_hash_close(ctx, *vp);
161       }
162       grn_hash_delete_by_id(ctx, ctx->impl->expr_vars, eid, NULL);
163     }
164   }
165   return ctx->rc;
166 }
167 
168 grn_obj *
grn_proc_get_info(grn_ctx * ctx,grn_user_data * user_data,grn_expr_var ** vars,unsigned int * nvars,grn_obj ** caller)169 grn_proc_get_info(grn_ctx *ctx, grn_user_data *user_data,
170                   grn_expr_var **vars, unsigned int *nvars, grn_obj **caller)
171 {
172   grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
173   if (caller) { *caller = pctx->caller; }
174   if (pctx->proc) {
175     if (vars) {
176       *vars = pctx->proc->vars;
177    // *vars = grn_expr_get_vars(ctx, (grn_obj *)pctx->proc, nvars);
178     }
179     if (nvars) { *nvars = pctx->proc->nvars; }
180   } else {
181     if (vars) { *vars = NULL; }
182     if (nvars) { *nvars = 0; }
183   }
184   return (grn_obj *)pctx->proc;
185 }
186 
187 grn_obj *
grn_proc_get_vars(grn_ctx * ctx,grn_user_data * user_data)188 grn_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data)
189 {
190   uint32_t n;
191   grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
192   if (pctx->proc) {
193     return (grn_obj *)grn_expr_get_vars(ctx, (grn_obj *)pctx->proc, &n);
194   } else {
195     return NULL;
196   }
197 }
198 
199 grn_obj *
grn_proc_get_var(grn_ctx * ctx,grn_user_data * user_data,const char * name,unsigned int name_size)200 grn_proc_get_var(grn_ctx *ctx, grn_user_data *user_data, const char *name, unsigned int name_size)
201 {
202   grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
203   return pctx->proc ? grn_expr_get_var(ctx, (grn_obj *)pctx->proc, name, name_size) : NULL;
204 }
205 
206 grn_obj *
grn_proc_get_var_by_offset(grn_ctx * ctx,grn_user_data * user_data,unsigned int offset)207 grn_proc_get_var_by_offset(grn_ctx *ctx, grn_user_data *user_data, unsigned int offset)
208 {
209   grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
210   return pctx->proc ? grn_expr_get_var_by_offset(ctx, (grn_obj *)pctx->proc, offset) : NULL;
211 }
212 
213 grn_obj *
grn_proc_get_or_add_var(grn_ctx * ctx,grn_user_data * user_data,const char * name,unsigned int name_size)214 grn_proc_get_or_add_var(grn_ctx *ctx, grn_user_data *user_data,
215                         const char *name, unsigned int name_size)
216 {
217   grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
218   return pctx->proc ? grn_expr_get_or_add_var(ctx, (grn_obj *)pctx->proc, name, name_size) : NULL;
219 }
220 
221 grn_obj *
grn_proc_alloc(grn_ctx * ctx,grn_user_data * user_data,grn_id domain,unsigned char flags)222 grn_proc_alloc(grn_ctx *ctx, grn_user_data *user_data, grn_id domain, unsigned char flags)
223 {
224   grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
225   return pctx->caller ? grn_expr_alloc(ctx, (grn_obj *)pctx->caller, domain, flags) : NULL;
226 }
227 
228 grn_proc_type
grn_proc_get_type(grn_ctx * ctx,grn_obj * proc)229 grn_proc_get_type(grn_ctx *ctx, grn_obj *proc)
230 {
231   grn_proc *proc_ = (grn_proc *)proc;
232   return proc_ ? proc_->type : GRN_PROC_INVALID;
233 }
234 
235 grn_rc
grn_proc_set_selector(grn_ctx * ctx,grn_obj * proc,grn_selector_func selector)236 grn_proc_set_selector(grn_ctx *ctx, grn_obj *proc, grn_selector_func selector)
237 {
238   grn_proc *proc_ = (grn_proc *)proc;
239   if (!grn_obj_is_function_proc(ctx, proc)) {
240     return GRN_INVALID_ARGUMENT;
241   }
242   proc_->callbacks.function.selector = selector;
243   return GRN_SUCCESS;
244 }
245 
246 grn_rc
grn_proc_set_selector_operator(grn_ctx * ctx,grn_obj * proc,grn_operator op)247 grn_proc_set_selector_operator(grn_ctx *ctx, grn_obj *proc, grn_operator op)
248 {
249   grn_proc *proc_ = (grn_proc *)proc;
250   if (!grn_obj_is_function_proc(ctx, proc)) {
251     return GRN_INVALID_ARGUMENT;
252   }
253   proc_->callbacks.function.selector_op = op;
254   return GRN_SUCCESS;
255 }
256 
257 grn_operator
grn_proc_get_selector_operator(grn_ctx * ctx,grn_obj * proc)258 grn_proc_get_selector_operator(grn_ctx *ctx, grn_obj *proc)
259 {
260   grn_proc *proc_ = (grn_proc *)proc;
261   if (!grn_obj_is_function_proc(ctx, proc)) {
262     return GRN_OP_NOP;
263   }
264   return proc_->callbacks.function.selector_op;
265 }
266 
267 grn_rc
grn_proc_set_is_stable(grn_ctx * ctx,grn_obj * proc,grn_bool is_stable)268 grn_proc_set_is_stable(grn_ctx *ctx, grn_obj *proc, grn_bool is_stable)
269 {
270   grn_proc *proc_ = (grn_proc *)proc;
271   if (!grn_obj_is_function_proc(ctx, proc)) {
272     return GRN_INVALID_ARGUMENT;
273   }
274   proc_->callbacks.function.is_stable = is_stable;
275   return GRN_SUCCESS;
276 }
277 
278 grn_bool
grn_proc_is_stable(grn_ctx * ctx,grn_obj * proc)279 grn_proc_is_stable(grn_ctx *ctx, grn_obj *proc)
280 {
281   grn_proc *proc_ = (grn_proc *)proc;
282   if (!grn_obj_is_function_proc(ctx, proc)) {
283     return GRN_FALSE;
284   }
285   return proc_->callbacks.function.is_stable;
286 }
287 
288 /* grn_expr */
289 
290 grn_obj *
grn_ctx_pop(grn_ctx * ctx)291 grn_ctx_pop(grn_ctx *ctx)
292 {
293   if (ctx && ctx->impl && ctx->impl->stack_curr) {
294     return ctx->impl->stack[--ctx->impl->stack_curr];
295   }
296   return NULL;
297 }
298 
299 grn_rc
grn_ctx_push(grn_ctx * ctx,grn_obj * obj)300 grn_ctx_push(grn_ctx *ctx, grn_obj *obj)
301 {
302   if (ctx && ctx->impl && ctx->impl->stack_curr < GRN_STACK_SIZE) {
303     ctx->impl->stack[ctx->impl->stack_curr++] = obj;
304     return GRN_SUCCESS;
305   }
306   return GRN_STACK_OVER_FLOW;
307 }
308 
309 grn_obj *
grn_expr_alloc_const(grn_ctx * ctx,grn_obj * expr)310 grn_expr_alloc_const(grn_ctx *ctx, grn_obj *expr)
311 {
312   grn_expr *e = (grn_expr *)expr;
313   uint32_t id = e->nconsts % GRN_EXPR_CONST_BLK_SIZE;
314   uint32_t blk_id = e->nconsts / GRN_EXPR_CONST_BLK_SIZE;
315 
316   if (id == 0) {
317     uint32_t nblks = blk_id + 1;
318     grn_obj **blks = (grn_obj **)GRN_REALLOC(e->const_blks,
319                                              sizeof(grn_obj *) * nblks);
320     if (!blks) {
321       ERR(GRN_NO_MEMORY_AVAILABLE, "realloc failed");
322       return NULL;
323     }
324     e->const_blks = blks;
325     blks[blk_id] = GRN_MALLOCN(grn_obj, GRN_EXPR_CONST_BLK_SIZE);
326     if (!blks[blk_id]) {
327       ERR(GRN_NO_MEMORY_AVAILABLE, "malloc failed");
328       return NULL;
329     }
330   }
331   e->nconsts++;
332   return &e->const_blks[blk_id][id];
333 }
334 
335 void
grn_obj_pack(grn_ctx * ctx,grn_obj * buf,grn_obj * obj)336 grn_obj_pack(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
337 {
338   grn_text_benc(ctx, buf, obj->header.type);
339   if (GRN_DB_OBJP(obj)) {
340     grn_text_benc(ctx, buf, DB_OBJ(obj)->id);
341   } else {
342     // todo : support vector, query, accessor, snip..
343     uint32_t vs = GRN_BULK_VSIZE(obj);
344     grn_text_benc(ctx, buf, obj->header.domain);
345     grn_text_benc(ctx, buf, vs);
346     if (vs) { GRN_TEXT_PUT(ctx, buf, GRN_BULK_HEAD(obj), vs); }
347   }
348 }
349 
350 const uint8_t *
grn_obj_unpack(grn_ctx * ctx,const uint8_t * p,const uint8_t * pe,uint8_t type,uint8_t flags,grn_obj * obj)351 grn_obj_unpack(grn_ctx *ctx, const uint8_t *p, const uint8_t *pe, uint8_t type, uint8_t flags, grn_obj *obj)
352 {
353   grn_id domain;
354   uint32_t vs;
355   GRN_B_DEC(domain, p);
356   GRN_OBJ_INIT(obj, type, flags, domain);
357   GRN_B_DEC(vs, p);
358   if (pe < p + vs) {
359     ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
360     return p;
361   }
362   grn_bulk_write(ctx, obj, (const char *)p, vs);
363   return p + vs;
364 }
365 
366 typedef enum {
367   GRN_EXPR_PACK_TYPE_NULL     = 0,
368   GRN_EXPR_PACK_TYPE_VARIABLE = 1,
369   GRN_EXPR_PACK_TYPE_OTHERS   = 2
370 } grn_expr_pack_type;
371 
372 void
grn_expr_pack(grn_ctx * ctx,grn_obj * buf,grn_obj * expr)373 grn_expr_pack(grn_ctx *ctx, grn_obj *buf, grn_obj *expr)
374 {
375   grn_expr_code *c;
376   grn_expr_var *v;
377   grn_expr *e = (grn_expr *)expr;
378   uint32_t i, j;
379   grn_text_benc(ctx, buf, e->nvars);
380   for (i = e->nvars, v = e->vars; i; i--, v++) {
381     grn_text_benc(ctx, buf, v->name_size);
382     if (v->name_size) { GRN_TEXT_PUT(ctx, buf, v->name, v->name_size); }
383     grn_obj_pack(ctx, buf, &v->value);
384   }
385   i = e->codes_curr;
386   grn_text_benc(ctx, buf, i);
387   for (c = e->codes; i; i--, c++) {
388     grn_text_benc(ctx, buf, c->op);
389     grn_text_benc(ctx, buf, c->nargs);
390     if (!c->value) {
391       grn_text_benc(ctx, buf, GRN_EXPR_PACK_TYPE_NULL);
392     } else {
393       for (j = 0, v = e->vars; j < e->nvars; j++, v++) {
394         if (&v->value == c->value) {
395           grn_text_benc(ctx, buf, GRN_EXPR_PACK_TYPE_VARIABLE);
396           grn_text_benc(ctx, buf, j);
397           break;
398         }
399       }
400       if (j == e->nvars) {
401         grn_text_benc(ctx, buf, GRN_EXPR_PACK_TYPE_OTHERS);
402         grn_obj_pack(ctx, buf, c->value);
403       }
404     }
405   }
406 }
407 
408 const uint8_t *
grn_expr_unpack(grn_ctx * ctx,const uint8_t * p,const uint8_t * pe,grn_obj * expr)409 grn_expr_unpack(grn_ctx *ctx, const uint8_t *p, const uint8_t *pe, grn_obj *expr)
410 {
411   grn_obj *v;
412   grn_expr_pack_type type;
413   uint32_t i, n, ns;
414   grn_expr_code *code;
415   grn_expr *e = (grn_expr *)expr;
416   GRN_B_DEC(n, p);
417   for (i = 0; i < n; i++) {
418     uint32_t object_type;
419     GRN_B_DEC(ns, p);
420     v = grn_expr_add_var(ctx, expr, ns ? (const char *)p : NULL, ns);
421     p += ns;
422     GRN_B_DEC(object_type, p);
423     if (GRN_TYPE <= object_type && object_type <= GRN_COLUMN_INDEX) { /* error */ }
424     p = grn_obj_unpack(ctx, p, pe, object_type, 0, v);
425     if (pe < p) {
426       ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
427       return p;
428     }
429   }
430   GRN_B_DEC(n, p);
431   /* confirm e->codes_size >= n */
432   e->codes_curr = n;
433   for (i = 0, code = e->codes; i < n; i++, code++) {
434     GRN_B_DEC(code->op, p);
435     GRN_B_DEC(code->nargs, p);
436     GRN_B_DEC(type, p);
437     switch (type) {
438     case GRN_EXPR_PACK_TYPE_NULL :
439       code->value = NULL;
440       break;
441     case GRN_EXPR_PACK_TYPE_VARIABLE :
442       {
443         uint32_t offset;
444         GRN_B_DEC(offset, p);
445         code->value = &e->vars[i].value;
446       }
447       break;
448     case GRN_EXPR_PACK_TYPE_OTHERS :
449       {
450         uint32_t object_type;
451         GRN_B_DEC(object_type, p);
452         if (GRN_TYPE <= object_type && object_type <= GRN_COLUMN_INDEX) {
453           grn_id id;
454           GRN_B_DEC(id, p);
455           code->value = grn_ctx_at(ctx, id);
456         } else {
457           if (!(v = grn_expr_alloc_const(ctx, expr))) { return NULL; }
458           p = grn_obj_unpack(ctx, p, pe, object_type, GRN_OBJ_EXPRCONST, v);
459           code->value = v;
460         }
461       }
462       break;
463     }
464     if (pe < p) {
465       ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
466       return p;
467     }
468   }
469   return p;
470 }
471 
472 grn_obj *
grn_expr_open(grn_ctx * ctx,grn_obj_spec * spec,const uint8_t * p,const uint8_t * pe)473 grn_expr_open(grn_ctx *ctx, grn_obj_spec *spec, const uint8_t *p, const uint8_t *pe)
474 {
475   grn_expr *expr = NULL;
476   if ((expr = GRN_MALLOCN(grn_expr, 1))) {
477     int size = GRN_STACK_SIZE;
478     expr->const_blks = NULL;
479     expr->nconsts = 0;
480     GRN_TEXT_INIT(&expr->name_buf, 0);
481     GRN_TEXT_INIT(&expr->dfi, 0);
482     GRN_PTR_INIT(&expr->objs, GRN_OBJ_VECTOR, GRN_ID_NIL);
483     expr->vars = NULL;
484     expr->nvars = 0;
485     GRN_DB_OBJ_SET_TYPE(expr, GRN_EXPR);
486     if ((expr->values = GRN_MALLOCN(grn_obj, size))) {
487       int i;
488       for (i = 0; i < size; i++) {
489         GRN_OBJ_INIT(&expr->values[i], GRN_BULK, GRN_OBJ_EXPRVALUE, GRN_ID_NIL);
490       }
491       expr->values_curr = 0;
492       expr->values_tail = 0;
493       expr->values_size = size;
494       if ((expr->codes = GRN_MALLOCN(grn_expr_code, size))) {
495         expr->codes_curr = 0;
496         expr->codes_size = size;
497         expr->obj.header = spec->header;
498         if (grn_expr_unpack(ctx, p, pe, (grn_obj *)expr) == pe) {
499           goto exit;
500         } else {
501           ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
502         }
503         GRN_FREE(expr->codes);
504       }
505       GRN_FREE(expr->values);
506     }
507     GRN_FREE(expr);
508     expr = NULL;
509   }
510 exit :
511   return (grn_obj *)expr;
512 }
513 
514 /* Pass ownership of `obj` to `expr`. */
515 void
grn_expr_take_obj(grn_ctx * ctx,grn_obj * expr,grn_obj * obj)516 grn_expr_take_obj(grn_ctx *ctx, grn_obj *expr, grn_obj *obj)
517 {
518   grn_expr *e = (grn_expr *)expr;
519   GRN_PTR_PUT(ctx, &(e->objs), obj);
520 }
521 
522 /* data flow info */
523 typedef struct {
524   grn_expr_code *code;
525   grn_id domain;
526   unsigned char type;
527 } grn_expr_dfi;
528 
529 static grn_expr_dfi *
grn_expr_dfi_pop(grn_expr * expr)530 grn_expr_dfi_pop(grn_expr *expr)
531 {
532   if (GRN_BULK_VSIZE(&expr->dfi) >= sizeof(grn_expr_dfi)) {
533     grn_expr_dfi *dfi;
534     GRN_BULK_INCR_LEN(&expr->dfi, -((ssize_t)(sizeof(grn_expr_dfi))));
535     dfi = (grn_expr_dfi *)GRN_BULK_CURR(&expr->dfi);
536     expr->code0 = dfi->code;
537     return dfi;
538   } else {
539     expr->code0 = NULL;
540     return NULL;
541   }
542 }
543 
544 static void
grn_expr_dfi_put(grn_ctx * ctx,grn_expr * expr,uint8_t type,grn_id domain,grn_expr_code * code)545 grn_expr_dfi_put(grn_ctx *ctx, grn_expr *expr, uint8_t type, grn_id domain,
546                  grn_expr_code *code)
547 {
548   grn_expr_dfi dfi;
549   dfi.type = type;
550   dfi.domain = domain;
551   dfi.code = code;
552   if (expr->code0) {
553     expr->code0->modify = code ? (code - expr->code0) : 0;
554   }
555   grn_bulk_write(ctx, &expr->dfi, (char *)&dfi, sizeof(grn_expr_dfi));
556   expr->code0 = NULL;
557 }
558 
559 grn_obj *
grn_expr_create(grn_ctx * ctx,const char * name,unsigned int name_size)560 grn_expr_create(grn_ctx *ctx, const char *name, unsigned int name_size)
561 {
562   grn_id id;
563   grn_obj *db;
564   grn_expr *expr = NULL;
565   if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
566     ERR(GRN_INVALID_ARGUMENT, "db not initialized");
567     return NULL;
568   }
569   if (name_size) {
570     ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
571         "[expr][create] named expression isn't implemented yet");
572     return NULL;
573   }
574   GRN_API_ENTER;
575   if (grn_db_check_name(ctx, name, name_size)) {
576     GRN_DB_CHECK_NAME_ERR("[expr][create]", name, name_size);
577     GRN_API_RETURN(NULL);
578   }
579   if (!GRN_DB_P(db)) {
580     ERR(GRN_INVALID_ARGUMENT, "named expr is not supported");
581     GRN_API_RETURN(NULL);
582   }
583   id = grn_obj_register(ctx, db, name, name_size);
584   if (id && (expr = GRN_MALLOCN(grn_expr, 1))) {
585     int size = GRN_STACK_SIZE;
586     expr->const_blks = NULL;
587     expr->nconsts = 0;
588     GRN_TEXT_INIT(&expr->name_buf, 0);
589     GRN_TEXT_INIT(&expr->dfi, 0);
590     GRN_PTR_INIT(&expr->objs, GRN_OBJ_VECTOR, GRN_ID_NIL);
591     expr->code0 = NULL;
592     expr->vars = NULL;
593     expr->nvars = 0;
594     expr->cacheable = 1;
595     expr->taintable = 0;
596     expr->values_curr = 0;
597     expr->values_tail = 0;
598     expr->values_size = size;
599     expr->codes_curr = 0;
600     expr->codes_size = size;
601     GRN_DB_OBJ_SET_TYPE(expr, GRN_EXPR);
602     expr->obj.header.domain = GRN_ID_NIL;
603     expr->obj.range = GRN_ID_NIL;
604     if (!grn_db_obj_init(ctx, db, id, DB_OBJ(expr))) {
605       if ((expr->values = GRN_MALLOCN(grn_obj, size))) {
606         int i;
607         for (i = 0; i < size; i++) {
608           GRN_OBJ_INIT(&expr->values[i], GRN_BULK, GRN_OBJ_EXPRVALUE, GRN_ID_NIL);
609         }
610         if ((expr->codes = GRN_MALLOCN(grn_expr_code, size))) {
611           goto exit;
612         }
613         GRN_FREE(expr->values);
614       }
615     }
616     GRN_FREE(expr);
617     expr = NULL;
618   }
619 exit :
620   GRN_API_RETURN((grn_obj *)expr);
621 }
622 
623 grn_rc
grn_expr_close(grn_ctx * ctx,grn_obj * expr)624 grn_expr_close(grn_ctx *ctx, grn_obj *expr)
625 {
626   uint32_t i, j;
627   grn_expr *e = (grn_expr *)expr;
628   GRN_API_ENTER;
629   /*
630   if (e->obj.header.domain) {
631     grn_hash_delete(ctx, ctx->impl->qe, &e->obj.header.domain, sizeof(grn_id), NULL);
632   }
633   */
634   grn_expr_clear_vars(ctx, expr);
635   if (e->const_blks) {
636     uint32_t nblks = e->nconsts + GRN_EXPR_CONST_BLK_SIZE - 1;
637     nblks /= GRN_EXPR_CONST_BLK_SIZE;
638     for (i = 0; i < nblks; i++) {
639       uint32_t end;
640       if (i < nblks - 1) {
641         end = GRN_EXPR_CONST_BLK_SIZE;
642       } else {
643         end = ((e->nconsts - 1) % GRN_EXPR_CONST_BLK_SIZE) + 1;
644       }
645       for (j = 0; j < end; j++) {
646         grn_obj *const_obj = &e->const_blks[i][j];
647         grn_obj_close(ctx, const_obj);
648       }
649       GRN_FREE(e->const_blks[i]);
650     }
651     GRN_FREE(e->const_blks);
652   }
653   grn_obj_close(ctx, &e->name_buf);
654   grn_obj_close(ctx, &e->dfi);
655   for (;;) {
656     grn_obj *obj;
657     GRN_PTR_POP(&e->objs, obj);
658     if (obj) {
659 #ifdef USE_MEMORY_DEBUG
660       grn_obj_unlink(ctx, obj);
661 #else
662       if (obj->header.type) {
663         if (obj->header.type == GRN_TABLE_HASH_KEY &&
664             ((grn_hash *)obj)->value_size == sizeof(grn_obj)) {
665           grn_obj *value;
666           GRN_HASH_EACH(ctx, (grn_hash *)obj, id, NULL, NULL, (void **)&value, {
667             GRN_OBJ_FIN(ctx, value);
668           });
669         }
670         grn_obj_unlink(ctx, obj);
671       } else {
672         GRN_LOG(ctx, GRN_LOG_WARNING, "GRN_VOID object is tried to be unlinked");
673       }
674 #endif
675     } else { break; }
676   }
677   grn_obj_close(ctx, &e->objs);
678   for (i = 0; i < e->nvars; i++) {
679     grn_obj_close(ctx, &e->vars[i].value);
680   }
681   if (e->vars) { GRN_FREE(e->vars); }
682   for (i = 0; i < e->values_tail; i++) {
683     grn_obj_close(ctx, &e->values[i]);
684   }
685   GRN_FREE(e->values);
686   GRN_FREE(e->codes);
687   GRN_FREE(e);
688   GRN_API_RETURN(ctx->rc);
689 }
690 
691 grn_obj *
grn_expr_add_var(grn_ctx * ctx,grn_obj * expr,const char * name,unsigned int name_size)692 grn_expr_add_var(grn_ctx *ctx, grn_obj *expr, const char *name, unsigned int name_size)
693 {
694   uint32_t i;
695   char *p;
696   grn_expr_var *v;
697   grn_obj *res = NULL;
698   grn_expr *e = (grn_expr *)expr;
699   GRN_API_ENTER;
700   if (DB_OBJ(expr)->id & GRN_OBJ_TMP_OBJECT) {
701     res = grn_expr_get_or_add_var(ctx, expr, name, name_size);
702   } else {
703     if (!e->vars) {
704       if (!(e->vars = GRN_MALLOCN(grn_expr_var, GRN_STACK_SIZE))) {
705         ERR(GRN_NO_MEMORY_AVAILABLE, "malloc failed");
706       }
707     }
708     if (e->vars && e->nvars < GRN_STACK_SIZE) {
709       v = e->vars + e->nvars++;
710       if (name_size) {
711         GRN_TEXT_PUT(ctx, &e->name_buf, name, name_size);
712       } else {
713         uint32_t ol = GRN_TEXT_LEN(&e->name_buf);
714         GRN_TEXT_PUTC(ctx, &e->name_buf, '$');
715         grn_text_itoa(ctx, &e->name_buf, e->nvars);
716         name_size = GRN_TEXT_LEN(&e->name_buf) - ol;
717       }
718       v->name_size = name_size;
719       res = &v->value;
720       GRN_VOID_INIT(res);
721       for (i = e->nvars, p = GRN_TEXT_VALUE(&e->name_buf), v = e->vars; i; i--, v++) {
722         v->name = p;
723         p += v->name_size;
724       }
725     }
726   }
727   GRN_API_RETURN(res);
728 }
729 
730 grn_obj *
grn_expr_get_var(grn_ctx * ctx,grn_obj * expr,const char * name,unsigned int name_size)731 grn_expr_get_var(grn_ctx *ctx, grn_obj *expr, const char *name, unsigned int name_size)
732 {
733   uint32_t n;
734   grn_obj *res = NULL;
735   grn_hash *vars = grn_expr_get_vars(ctx, expr, &n);
736   if (vars) { grn_hash_get(ctx, vars, name, name_size, (void **)&res); }
737   return res;
738 }
739 
740 grn_obj *
grn_expr_get_or_add_var(grn_ctx * ctx,grn_obj * expr,const char * name,unsigned int name_size)741 grn_expr_get_or_add_var(grn_ctx *ctx, grn_obj *expr, const char *name, unsigned int name_size)
742 {
743   uint32_t n;
744   grn_obj *res = NULL;
745   grn_hash *vars = grn_expr_get_vars(ctx, expr, &n);
746   if (vars) {
747     int added = 0;
748     char name_buf[16];
749     if (!name_size) {
750       char *rest;
751       name_buf[0] = '$';
752       grn_itoa((int)GRN_HASH_SIZE(vars) + 1, name_buf + 1, name_buf + 16, &rest);
753       name_size = rest - name_buf;
754       name = name_buf;
755     }
756     grn_hash_add(ctx, vars, name, name_size, (void **)&res, &added);
757     if (added) { GRN_TEXT_INIT(res, 0); }
758   }
759   return res;
760 }
761 
762 grn_obj *
grn_expr_get_var_by_offset(grn_ctx * ctx,grn_obj * expr,unsigned int offset)763 grn_expr_get_var_by_offset(grn_ctx *ctx, grn_obj *expr, unsigned int offset)
764 {
765   uint32_t n;
766   grn_obj *res = NULL;
767   grn_hash *vars = grn_expr_get_vars(ctx, expr, &n);
768   if (vars) { res = (grn_obj *)grn_hash_get_value_(ctx, vars, offset + 1, NULL); }
769   return res;
770 }
771 
772 #define EXPRVP(x) ((x)->header.impl_flags & GRN_OBJ_EXPRVALUE)
773 
774 #define CONSTP(obj) ((obj) && ((obj)->header.impl_flags & GRN_OBJ_EXPRCONST))
775 
776 #define PUSH_CODE(e,o,v,n,c) do {\
777   (c) = &(e)->codes[e->codes_curr++];\
778   (c)->value = (v);\
779   (c)->nargs = (n);\
780   (c)->op = (o);\
781   (c)->flags = 0;\
782   (c)->modify = 0;\
783 } while (0)
784 
785 #define APPEND_UNARY_MINUS_OP(e) do {                           \
786   grn_expr_code *code_;                                         \
787   grn_id domain;                                                \
788   unsigned char type;                                           \
789   grn_obj *x;                                                   \
790   dfi = grn_expr_dfi_pop(e);                                    \
791   code_ = dfi->code;                                            \
792   domain = dfi->domain;                                         \
793   type = dfi->type;                                             \
794   x = code_->value;                                             \
795   if (CONSTP(x)) {                                              \
796     switch (domain) {                                           \
797     case GRN_DB_INT32:                                          \
798       {                                                         \
799         int value;                                              \
800         value = GRN_INT32_VALUE(x);                             \
801         if (value == (int)0x80000000) {                         \
802           domain = GRN_DB_INT64;                                \
803           x->header.domain = domain;                            \
804           GRN_INT64_SET(ctx, x, -((long long int)value));       \
805         } else {                                                \
806           GRN_INT32_SET(ctx, x, -value);                        \
807         }                                                       \
808       }                                                         \
809       break;                                                    \
810     case GRN_DB_UINT32:                                         \
811       {                                                         \
812         unsigned int value;                                     \
813         value = GRN_UINT32_VALUE(x);                            \
814         if (value > (unsigned int)0x80000000) {                 \
815           domain = GRN_DB_INT64;                                \
816           x->header.domain = domain;                            \
817           GRN_INT64_SET(ctx, x, -((long long int)value));       \
818         } else {                                                \
819           domain = GRN_DB_INT32;                                \
820           x->header.domain = domain;                            \
821           GRN_INT32_SET(ctx, x, -((int)value));                 \
822         }                                                       \
823       }                                                         \
824       break;                                                    \
825     case GRN_DB_INT64:                                          \
826       GRN_INT64_SET(ctx, x, -GRN_INT64_VALUE(x));               \
827       break;                                                    \
828     case GRN_DB_FLOAT:                                          \
829       GRN_FLOAT_SET(ctx, x, -GRN_FLOAT_VALUE(x));               \
830       break;                                                    \
831     default:                                                    \
832       PUSH_CODE(e, op, obj, nargs, code);                       \
833       break;                                                    \
834     }                                                           \
835   } else {                                                      \
836     PUSH_CODE(e, op, obj, nargs, code);                         \
837   }                                                             \
838   grn_expr_dfi_put(ctx, e, type, domain, code_);                \
839 } while (0)
840 
841 #define PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code) do { \
842   PUSH_CODE(e, op, obj, nargs, code);                           \
843   {                                                             \
844     int i = nargs;                                              \
845     while (i--) {                                               \
846       dfi = grn_expr_dfi_pop(e);                                \
847     }                                                           \
848   }                                                             \
849   grn_expr_dfi_put(ctx, e, type, domain, code);                 \
850 } while (0)
851 
852 static void
grn_expr_append_obj_resolve_const(grn_ctx * ctx,grn_obj * obj,grn_id to_domain)853 grn_expr_append_obj_resolve_const(grn_ctx *ctx,
854                                   grn_obj *obj,
855                                   grn_id to_domain)
856 {
857   grn_obj dest;
858 
859   GRN_OBJ_INIT(&dest, GRN_BULK, 0, to_domain);
860   if (!grn_obj_cast(ctx, obj, &dest, GRN_FALSE)) {
861     grn_obj_reinit(ctx, obj, to_domain, 0);
862     grn_bulk_write(ctx, obj, GRN_BULK_HEAD(&dest), GRN_BULK_VSIZE(&dest));
863   }
864   GRN_OBJ_FIN(ctx, &dest);
865 }
866 
867 grn_obj *
grn_expr_append_obj(grn_ctx * ctx,grn_obj * expr,grn_obj * obj,grn_operator op,int nargs)868 grn_expr_append_obj(grn_ctx *ctx, grn_obj *expr, grn_obj *obj, grn_operator op, int nargs)
869 {
870   uint8_t type = GRN_VOID;
871   grn_id domain = GRN_ID_NIL;
872   grn_expr_dfi *dfi;
873   grn_expr_code *code;
874   grn_obj *res = NULL;
875   grn_expr *e = (grn_expr *)expr;
876   GRN_API_ENTER;
877   if (e->codes_curr >= e->codes_size) {
878     grn_expr_dfi *dfis = (grn_expr_dfi *)GRN_BULK_HEAD(&e->dfi);
879     size_t i, n_dfis = GRN_BULK_VSIZE(&e->dfi) / sizeof(grn_expr_dfi);
880     uint32_t new_codes_size = e->codes_size * 2;
881     size_t n_bytes = sizeof(grn_expr_code) * new_codes_size;
882     grn_expr_code *new_codes = (grn_expr_code *)GRN_MALLOC(n_bytes);
883     if (!new_codes) {
884       ERR(GRN_NO_MEMORY_AVAILABLE, "stack is full");
885       goto exit;
886     }
887     grn_memcpy(new_codes, e->codes, sizeof(grn_expr_code) * e->codes_size);
888     if (e->code0 >= e->codes && e->code0 < e->codes + e->codes_size) {
889       e->code0 = new_codes + (e->code0 - e->codes);
890     }
891     for (i = 0; i < n_dfis; i++) {
892       if (dfis[i].code >= e->codes && dfis[i].code < e->codes + e->codes_size) {
893         dfis[i].code = new_codes + (dfis[i].code - e->codes);
894       }
895     }
896     GRN_FREE(e->codes);
897     e->codes = new_codes;
898     e->codes_size = new_codes_size;
899   }
900   {
901     switch (op) {
902     case GRN_OP_PUSH :
903       if (obj) {
904         PUSH_CODE(e, op, obj, nargs, code);
905         grn_expr_dfi_put(ctx, e, obj->header.type, GRN_OBJ_GET_DOMAIN(obj),
906                          code);
907       } else {
908         ERR(GRN_INVALID_ARGUMENT, "obj not assigned for GRN_OP_PUSH");
909         goto exit;
910       }
911       break;
912     case GRN_OP_NOP :
913       /* nop */
914       break;
915     case GRN_OP_POP :
916       if (obj) {
917         ERR(GRN_INVALID_ARGUMENT, "obj assigned for GRN_OP_POP");
918         goto exit;
919       } else {
920         PUSH_CODE(e, op, obj, nargs, code);
921         dfi = grn_expr_dfi_pop(e);
922       }
923       break;
924     case GRN_OP_CALL :
925       {
926         grn_obj *proc = NULL;
927         /*
928          * This is for keeping backward compatibility. We want to
929          * handle all "nargs" means that "N items on stack are used (N
930          * items are popped)" but "nargs" for OP_CALL is used as "N
931          * arguments" not "N items on stack are used" historically. It
932          * means that called function isn't included in "nargs".
933          *
934          * We adjust "nargs" here to handle "code->nargs" more easily.
935          * If we don't adjust "nargs" here, we need to care
936          * "code->nargs" at all locations that use "code->nargs". We
937          * need to use "code->nargs + 1" for OP_CALL and "code->nargs"
938          * for not OP_CALL to compute N items should be popped. It's
939          * wired. So we adjust "nargs" here.
940          */
941         nargs++;
942         if (e->codes_curr - (nargs - 1) > 0) {
943           int i;
944           grn_expr_code *code;
945           code = &(e->codes[e->codes_curr - 1]);
946           for (i = 0; i < nargs - 1; i++) {
947             int rest_n_codes = 1;
948             while (rest_n_codes > 0) {
949               rest_n_codes += code->nargs;
950               if (code->value) {
951                 rest_n_codes--;
952               }
953               rest_n_codes--;
954               code--;
955             }
956           }
957           proc = code->value;
958         }
959         if (!proc) {
960           ERR(GRN_INVALID_ARGUMENT, "invalid function call expression");
961           goto exit;
962         }
963         if (!(grn_obj_is_function_proc(ctx, proc) ||
964               grn_obj_is_scorer_proc(ctx, proc) ||
965               grn_obj_is_window_function_proc(ctx, proc))) {
966           grn_obj buffer;
967 
968           GRN_TEXT_INIT(&buffer, 0);
969           switch (proc->header.type) {
970           case GRN_TABLE_HASH_KEY:
971           case GRN_TABLE_PAT_KEY:
972           case GRN_TABLE_NO_KEY:
973           case GRN_COLUMN_FIX_SIZE:
974           case GRN_COLUMN_VAR_SIZE:
975           case GRN_COLUMN_INDEX:
976             grn_inspect_name(ctx, &buffer, proc);
977             break;
978           default:
979             grn_inspect(ctx, &buffer, proc);
980             break;
981           }
982           ERR(GRN_INVALID_ARGUMENT, "invalid function: <%.*s>",
983               (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
984           GRN_OBJ_FIN(ctx, &buffer);
985           goto exit;
986         }
987 
988         PUSH_CODE(e, op, obj, nargs, code);
989         {
990           int i = nargs - 1;
991           while (i--) { dfi = grn_expr_dfi_pop(e); }
992         }
993         if (!obj) { dfi = grn_expr_dfi_pop(e); }
994         // todo : increment e->values_tail.
995         /* cannot identify type of return value */
996         grn_expr_dfi_put(ctx, e, type, domain, code);
997         if (!grn_proc_is_stable(ctx, proc)) {
998           e->cacheable = 0;
999         }
1000       }
1001       break;
1002     case GRN_OP_INTERN :
1003       if (obj && CONSTP(obj)) {
1004         grn_obj *value;
1005         value = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj));
1006         if (!value) { value = grn_ctx_get(ctx, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); }
1007         if (value) {
1008           obj = value;
1009           op = GRN_OP_PUSH;
1010           type = obj->header.type;
1011           domain = GRN_OBJ_GET_DOMAIN(obj);
1012         }
1013       }
1014       PUSH_CODE(e, op, obj, nargs, code);
1015       grn_expr_dfi_put(ctx, e, type, domain, code);
1016       break;
1017     case GRN_OP_EQUAL :
1018       PUSH_CODE(e, op, obj, nargs, code);
1019       if (nargs) {
1020         grn_id xd, yd = GRN_ID_NIL;
1021         grn_obj *x, *y = NULL;
1022         int i = nargs - 1;
1023         if (obj) {
1024           xd = GRN_OBJ_GET_DOMAIN(obj);
1025           x = obj;
1026         } else {
1027           dfi = grn_expr_dfi_pop(e);
1028           x = dfi->code->value;
1029           xd = dfi->domain;
1030         }
1031         while (i--) {
1032           dfi = grn_expr_dfi_pop(e);
1033           y = dfi->code->value;
1034           yd = dfi->domain;
1035         }
1036         if (CONSTP(x)) {
1037           if (CONSTP(y)) {
1038             /* todo */
1039           } else {
1040             if (xd != yd) {
1041               grn_expr_append_obj_resolve_const(ctx, x, yd);
1042             }
1043           }
1044         } else {
1045           if (CONSTP(y)) {
1046             if (xd != yd) {
1047               grn_expr_append_obj_resolve_const(ctx, y, xd);
1048             }
1049           }
1050         }
1051       }
1052       grn_expr_dfi_put(ctx, e, type, domain, code);
1053       break;
1054     case GRN_OP_TABLE_CREATE :
1055     case GRN_OP_EXPR_GET_VAR :
1056     case GRN_OP_MATCH :
1057     case GRN_OP_NEAR :
1058     case GRN_OP_NEAR2 :
1059     case GRN_OP_SIMILAR :
1060     case GRN_OP_PREFIX :
1061     case GRN_OP_SUFFIX :
1062     case GRN_OP_NOT_EQUAL :
1063     case GRN_OP_LESS :
1064     case GRN_OP_GREATER :
1065     case GRN_OP_LESS_EQUAL :
1066     case GRN_OP_GREATER_EQUAL :
1067     case GRN_OP_GEO_DISTANCE1 :
1068     case GRN_OP_GEO_DISTANCE2 :
1069     case GRN_OP_GEO_DISTANCE3 :
1070     case GRN_OP_GEO_DISTANCE4 :
1071     case GRN_OP_GEO_WITHINP5 :
1072     case GRN_OP_GEO_WITHINP6 :
1073     case GRN_OP_GEO_WITHINP8 :
1074     case GRN_OP_OBJ_SEARCH :
1075     case GRN_OP_TABLE_SELECT :
1076     case GRN_OP_TABLE_SORT :
1077     case GRN_OP_TABLE_GROUP :
1078     case GRN_OP_JSON_PUT :
1079     case GRN_OP_GET_REF :
1080     case GRN_OP_ADJUST :
1081     case GRN_OP_TERM_EXTRACT :
1082     case GRN_OP_REGEXP :
1083       PUSH_CODE(e, op, obj, nargs, code);
1084       if (nargs) {
1085         int i = nargs - 1;
1086         if (!obj) { dfi = grn_expr_dfi_pop(e); }
1087         while (i--) { dfi = grn_expr_dfi_pop(e); }
1088       }
1089       grn_expr_dfi_put(ctx, e, type, domain, code);
1090       break;
1091     case GRN_OP_AND :
1092     case GRN_OP_OR :
1093     case GRN_OP_AND_NOT :
1094       PUSH_CODE(e, op, obj, nargs, code);
1095       if (nargs != 2) {
1096         GRN_LOG(ctx, GRN_LOG_WARNING, "nargs(%d) != 2 in relative op", nargs);
1097       }
1098       if (obj) {
1099         GRN_LOG(ctx, GRN_LOG_WARNING, "obj assigned to relative op");
1100       }
1101       {
1102         int i = nargs;
1103         while (i--) {
1104           dfi = grn_expr_dfi_pop(e);
1105           if (dfi) {
1106             dfi->code->flags |= GRN_EXPR_CODE_RELATIONAL_EXPRESSION;
1107           } else {
1108             ERR(GRN_SYNTAX_ERROR, "stack under flow in relative op");
1109           }
1110         }
1111       }
1112       grn_expr_dfi_put(ctx, e, type, domain, code);
1113       break;
1114     case GRN_OP_NOT :
1115       if (nargs == 1) {
1116         PUSH_CODE(e, op, obj, nargs, code);
1117       }
1118       break;
1119     case GRN_OP_PLUS :
1120       if (nargs > 1) {
1121         PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code);
1122       }
1123       break;
1124     case GRN_OP_MINUS :
1125       if (nargs == 1) {
1126         APPEND_UNARY_MINUS_OP(e);
1127       } else {
1128         PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code);
1129       }
1130       break;
1131     case GRN_OP_BITWISE_NOT :
1132       dfi = grn_expr_dfi_pop(e);
1133       if (dfi) {
1134         type = dfi->type;
1135         domain = dfi->domain;
1136         switch (domain) {
1137         case GRN_DB_UINT8 :
1138           domain = GRN_DB_INT16;
1139           break;
1140         case GRN_DB_UINT16 :
1141           domain = GRN_DB_INT32;
1142           break;
1143         case GRN_DB_UINT32 :
1144         case GRN_DB_UINT64 :
1145           domain = GRN_DB_INT64;
1146           break;
1147         }
1148       }
1149       PUSH_CODE(e, op, obj, nargs, code);
1150       grn_expr_dfi_put(ctx, e, type, domain, code);
1151       break;
1152     case GRN_OP_STAR :
1153     case GRN_OP_SLASH :
1154     case GRN_OP_MOD :
1155     case GRN_OP_SHIFTL :
1156     case GRN_OP_SHIFTR :
1157     case GRN_OP_SHIFTRR :
1158     case GRN_OP_BITWISE_OR :
1159     case GRN_OP_BITWISE_XOR :
1160     case GRN_OP_BITWISE_AND :
1161       PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code);
1162       break;
1163     case GRN_OP_INCR :
1164     case GRN_OP_DECR :
1165     case GRN_OP_INCR_POST :
1166     case GRN_OP_DECR_POST :
1167       {
1168         dfi = grn_expr_dfi_pop(e);
1169         if (dfi) {
1170           type = dfi->type;
1171           domain = dfi->domain;
1172           if (dfi->code) {
1173             if (dfi->code->op == GRN_OP_GET_VALUE) {
1174               dfi->code->op = GRN_OP_GET_REF;
1175             }
1176             if (dfi->code->value && grn_obj_is_persistent(ctx, dfi->code->value)) {
1177               e->cacheable = 0;
1178               e->taintable = 1;
1179             }
1180           }
1181         }
1182         PUSH_CODE(e, op, obj, nargs, code);
1183       }
1184       grn_expr_dfi_put(ctx, e, type, domain, code);
1185       break;
1186     case GRN_OP_GET_VALUE :
1187       {
1188         grn_id vdomain = GRN_ID_NIL;
1189         if (obj) {
1190           if (nargs == 1) {
1191             grn_obj *v = grn_expr_get_var_by_offset(ctx, expr, 0);
1192             if (v) { vdomain = GRN_OBJ_GET_DOMAIN(v); }
1193           } else {
1194             dfi = grn_expr_dfi_pop(e);
1195             vdomain = dfi->domain;
1196           }
1197           if (vdomain && CONSTP(obj) && obj->header.type == GRN_BULK) {
1198             grn_obj *table = grn_ctx_at(ctx, vdomain);
1199             grn_obj *col = grn_obj_column(ctx, table, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
1200             if (col) {
1201               obj = col;
1202               type = col->header.type;
1203               domain = grn_obj_get_range(ctx, col);
1204               grn_expr_take_obj(ctx, (grn_obj *)e, col);
1205             }
1206           } else {
1207             domain = grn_obj_get_range(ctx, obj);
1208           }
1209           PUSH_CODE(e, op, obj, nargs, code);
1210         } else {
1211           grn_expr_dfi *dfi0;
1212           dfi0 = grn_expr_dfi_pop(e);
1213           if (nargs == 1) {
1214             grn_obj *v = grn_expr_get_var_by_offset(ctx, expr, 0);
1215             if (v) { vdomain = GRN_OBJ_GET_DOMAIN(v); }
1216           } else {
1217             dfi = grn_expr_dfi_pop(e);
1218             vdomain = dfi->domain;
1219           }
1220           if (dfi0->code->op == GRN_OP_PUSH) {
1221             dfi0->code->op = op;
1222             dfi0->code->nargs = nargs;
1223             obj = dfi0->code->value;
1224             if (vdomain && obj && CONSTP(obj) && obj->header.type == GRN_BULK) {
1225               grn_obj *table = grn_ctx_at(ctx, vdomain);
1226               grn_obj *col = grn_obj_column(ctx, table, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
1227               if (col) {
1228                 dfi0->code->value = col;
1229                 type = col->header.type;
1230                 domain = grn_obj_get_range(ctx, col);
1231                 grn_obj_unlink(ctx, col);
1232               }
1233             } else {
1234               domain = grn_obj_get_range(ctx, obj);
1235             }
1236             code = dfi0->code;
1237           } else {
1238             PUSH_CODE(e, op, obj, nargs, code);
1239           }
1240         }
1241       }
1242       grn_expr_dfi_put(ctx, e, type, domain, code);
1243       break;
1244     case GRN_OP_ASSIGN :
1245     case GRN_OP_STAR_ASSIGN :
1246     case GRN_OP_SLASH_ASSIGN :
1247     case GRN_OP_MOD_ASSIGN :
1248     case GRN_OP_PLUS_ASSIGN :
1249     case GRN_OP_MINUS_ASSIGN :
1250     case GRN_OP_SHIFTL_ASSIGN :
1251     case GRN_OP_SHIFTR_ASSIGN :
1252     case GRN_OP_SHIFTRR_ASSIGN :
1253     case GRN_OP_AND_ASSIGN :
1254     case GRN_OP_OR_ASSIGN :
1255     case GRN_OP_XOR_ASSIGN :
1256       {
1257         if (obj) {
1258           type = obj->header.type;
1259           domain = GRN_OBJ_GET_DOMAIN(obj);
1260         } else {
1261           dfi = grn_expr_dfi_pop(e);
1262           if (dfi) {
1263             type = dfi->type;
1264             domain = dfi->domain;
1265           }
1266         }
1267         dfi = grn_expr_dfi_pop(e);
1268         if (dfi && (dfi->code)) {
1269           if (dfi->code->op == GRN_OP_GET_VALUE) {
1270             dfi->code->op = GRN_OP_GET_REF;
1271           }
1272           if (dfi->code->value && grn_obj_is_persistent(ctx, dfi->code->value)) {
1273             e->cacheable = 0;
1274             e->taintable = 1;
1275           }
1276         }
1277         PUSH_CODE(e, op, obj, nargs, code);
1278       }
1279       grn_expr_dfi_put(ctx, e, type, domain, code);
1280       break;
1281     case GRN_OP_JUMP :
1282       dfi = grn_expr_dfi_pop(e);
1283       PUSH_CODE(e, op, obj, nargs, code);
1284       break;
1285     case GRN_OP_CJUMP :
1286       dfi = grn_expr_dfi_pop(e);
1287       PUSH_CODE(e, op, obj, nargs, code);
1288       break;
1289     case GRN_OP_COMMA :
1290       PUSH_CODE(e, op, obj, nargs, code);
1291       break;
1292     case GRN_OP_GET_MEMBER :
1293       dfi = grn_expr_dfi_pop(e);
1294       dfi = grn_expr_dfi_pop(e);
1295       if (dfi) {
1296         type = dfi->type;
1297         domain = dfi->domain;
1298         if (dfi->code) {
1299           if (dfi->code->op == GRN_OP_GET_VALUE) {
1300             dfi->code->op = GRN_OP_GET_REF;
1301           }
1302         }
1303       }
1304       PUSH_CODE(e, op, obj, nargs, code);
1305       grn_expr_dfi_put(ctx, e, type, domain, code);
1306       break;
1307     default :
1308       break;
1309     }
1310   }
1311 exit :
1312   if (!ctx->rc) { res = obj; }
1313   GRN_API_RETURN(res);
1314 }
1315 #undef PUSH_N_ARGS_ARITHMETIC_OP
1316 #undef APPEND_UNARY_MINUS_OP
1317 
1318 grn_obj *
grn_expr_append_const(grn_ctx * ctx,grn_obj * expr,grn_obj * obj,grn_operator op,int nargs)1319 grn_expr_append_const(grn_ctx *ctx, grn_obj *expr, grn_obj *obj,
1320                       grn_operator op, int nargs)
1321 {
1322   grn_obj *res = NULL;
1323   GRN_API_ENTER;
1324   if (!obj) {
1325     ERR(GRN_SYNTAX_ERROR, "constant is null");
1326     goto exit;
1327   }
1328   if (GRN_DB_OBJP(obj) || GRN_ACCESSORP(obj)) {
1329     res = obj;
1330   } else {
1331     if ((res = grn_expr_alloc_const(ctx, expr))) {
1332       switch (obj->header.type) {
1333       case GRN_VOID :
1334       case GRN_BULK :
1335       case GRN_UVECTOR :
1336         GRN_OBJ_INIT(res, obj->header.type, 0, obj->header.domain);
1337         grn_bulk_write(ctx, res, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
1338         break;
1339       default :
1340         res = NULL;
1341         ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "unsupported type");
1342         goto exit;
1343       }
1344       res->header.impl_flags |= GRN_OBJ_EXPRCONST;
1345     }
1346   }
1347   grn_expr_append_obj(ctx, expr, res, op, nargs); /* constant */
1348 exit :
1349   GRN_API_RETURN(res);
1350 }
1351 
1352 static grn_obj *
grn_expr_add_str(grn_ctx * ctx,grn_obj * expr,const char * str,unsigned int str_size)1353 grn_expr_add_str(grn_ctx *ctx, grn_obj *expr, const char *str, unsigned int str_size)
1354 {
1355   grn_obj *res = NULL;
1356   if ((res = grn_expr_alloc_const(ctx, expr))) {
1357     GRN_TEXT_INIT(res, 0);
1358     grn_bulk_write(ctx, res, str, str_size);
1359     res->header.impl_flags |= GRN_OBJ_EXPRCONST;
1360   }
1361   return res;
1362 }
1363 
1364 grn_obj *
grn_expr_append_const_str(grn_ctx * ctx,grn_obj * expr,const char * str,unsigned int str_size,grn_operator op,int nargs)1365 grn_expr_append_const_str(grn_ctx *ctx, grn_obj *expr, const char *str, unsigned int str_size,
1366                           grn_operator op, int nargs)
1367 {
1368   grn_obj *res;
1369   GRN_API_ENTER;
1370   res = grn_expr_add_str(ctx, expr, str, str_size);
1371   grn_expr_append_obj(ctx, expr, res, op, nargs); /* constant */
1372   GRN_API_RETURN(res);
1373 }
1374 
1375 grn_obj *
grn_expr_append_const_int(grn_ctx * ctx,grn_obj * expr,int i,grn_operator op,int nargs)1376 grn_expr_append_const_int(grn_ctx *ctx, grn_obj *expr, int i,
1377                           grn_operator op, int nargs)
1378 {
1379   grn_obj *res = NULL;
1380   GRN_API_ENTER;
1381   if ((res = grn_expr_alloc_const(ctx, expr))) {
1382     GRN_INT32_INIT(res, 0);
1383     GRN_INT32_SET(ctx, res, i);
1384     res->header.impl_flags |= GRN_OBJ_EXPRCONST;
1385   }
1386   grn_expr_append_obj(ctx, expr, res, op, nargs); /* constant */
1387   GRN_API_RETURN(res);
1388 }
1389 
1390 grn_rc
grn_expr_append_op(grn_ctx * ctx,grn_obj * expr,grn_operator op,int nargs)1391 grn_expr_append_op(grn_ctx *ctx, grn_obj *expr, grn_operator op, int nargs)
1392 {
1393   grn_expr_append_obj(ctx, expr, NULL, op, nargs);
1394   return ctx->rc;
1395 }
1396 
1397 grn_rc
grn_expr_compile(grn_ctx * ctx,grn_obj * expr)1398 grn_expr_compile(grn_ctx *ctx, grn_obj *expr)
1399 {
1400   grn_obj_spec_save(ctx, DB_OBJ(expr));
1401   return ctx->rc;
1402 }
1403 
1404 grn_obj *
grn_expr_rewrite(grn_ctx * ctx,grn_obj * expr)1405 grn_expr_rewrite(grn_ctx *ctx, grn_obj *expr)
1406 {
1407   grn_obj *rewritten = NULL;
1408 
1409   GRN_API_ENTER;
1410 
1411 #ifdef GRN_WITH_MRUBY
1412   grn_ctx_impl_mrb_ensure_init(ctx);
1413   if (ctx->rc != GRN_SUCCESS) {
1414     GRN_API_RETURN(NULL);
1415   }
1416   if (ctx->impl->mrb.state) {
1417     rewritten = grn_mrb_expr_rewrite(ctx, expr);
1418   }
1419 #endif
1420 
1421   GRN_API_RETURN(rewritten);
1422 }
1423 
1424 #define WITH_SPSAVE(block) do {\
1425   ctx->impl->stack_curr = sp - ctx->impl->stack;\
1426   e->values_curr = vp - e->values;\
1427   block\
1428   vp = e->values + e->values_curr;\
1429   sp = ctx->impl->stack + ctx->impl->stack_curr;\
1430   s0 = sp[-1];\
1431   s1 = sp[-2];\
1432 } while (0)
1433 
1434 #define GEO_RESOLUTION   3600000
1435 #define GEO_RADIOUS      6357303
1436 #define GEO_BES_C1       6334834
1437 #define GEO_BES_C2       6377397
1438 #define GEO_BES_C3       0.006674
1439 #define GEO_GRS_C1       6335439
1440 #define GEO_GRS_C2       6378137
1441 #define GEO_GRS_C3       0.006694
1442 #define GEO_INT2RAD(x)   ((M_PI * x) / (GEO_RESOLUTION * 180))
1443 
1444 #define VAR_SET_VALUE(ctx,var,value) do {\
1445   if (GRN_DB_OBJP(value)) {\
1446     (var)->header.type = GRN_PTR;\
1447     (var)->header.domain = DB_OBJ(value)->id;\
1448     GRN_PTR_SET(ctx, (var), (value));\
1449   } else {\
1450     (var)->header.type = (value)->header.type;\
1451     (var)->header.domain = (value)->header.domain;\
1452     GRN_TEXT_SET(ctx, (var), GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));\
1453   }\
1454 } while (0)
1455 
1456 grn_rc
grn_proc_call(grn_ctx * ctx,grn_obj * proc,int nargs,grn_obj * caller)1457 grn_proc_call(grn_ctx *ctx, grn_obj *proc, int nargs, grn_obj *caller)
1458 {
1459   grn_proc_ctx pctx;
1460   grn_obj *obj = NULL, **args;
1461   grn_proc *p = (grn_proc *)proc;
1462   if (nargs > ctx->impl->stack_curr) { return GRN_INVALID_ARGUMENT; }
1463   GRN_API_ENTER;
1464   if (grn_obj_is_selector_only_proc(ctx, proc)) {
1465     char name[GRN_TABLE_MAX_KEY_SIZE];
1466     int name_size;
1467     name_size = grn_obj_name(ctx, proc, name, GRN_TABLE_MAX_KEY_SIZE);
1468     ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
1469         "selector only proc can't be called: <%.*s>",
1470         name_size, name);
1471     GRN_API_RETURN(ctx->rc);
1472   }
1473   args = ctx->impl->stack + ctx->impl->stack_curr - nargs;
1474   pctx.proc = p;
1475   pctx.caller = caller;
1476   pctx.user_data.ptr = NULL;
1477   if (p->funcs[PROC_INIT]) {
1478     grn_obj *sub_obj;
1479     sub_obj = p->funcs[PROC_INIT](ctx, nargs, args, &pctx.user_data);
1480     if (sub_obj) {
1481       obj = sub_obj;
1482     }
1483   }
1484   pctx.phase = PROC_NEXT;
1485   if (p->funcs[PROC_NEXT]) {
1486     grn_obj *sub_obj;
1487     sub_obj = p->funcs[PROC_NEXT](ctx, nargs, args, &pctx.user_data);
1488     if (sub_obj) {
1489       obj = sub_obj;
1490     }
1491   }
1492   pctx.phase = PROC_FIN;
1493   if (p->funcs[PROC_FIN]) {
1494     grn_obj *sub_obj;
1495     sub_obj = p->funcs[PROC_FIN](ctx, nargs, args, &pctx.user_data);
1496     if (sub_obj) {
1497       obj = sub_obj;
1498     }
1499   }
1500   ctx->impl->stack_curr -= nargs;
1501   grn_ctx_push(ctx, obj);
1502   GRN_API_RETURN(ctx->rc);
1503 }
1504 
1505 #define PUSH1(v) do {\
1506   if (EXPRVP(v)) {\
1507     vp++;\
1508     if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
1509   }\
1510   s1 = s0;\
1511   *sp++ = s0 = v;\
1512 } while (0)
1513 
1514 #define POP1(v) do {\
1515   if (EXPRVP(s0)) { vp--; }\
1516   v = s0;\
1517   s0 = s1;\
1518   sp--;\
1519   if (sp < s_) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\
1520   s1 = sp[-2];\
1521 } while (0)
1522 
1523 #define ALLOC1(value) do {\
1524   s1 = s0;\
1525   *sp++ = s0 = value = vp++;\
1526   if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
1527 } while (0)
1528 
1529 #define POP1ALLOC1(arg,value) do {\
1530   arg = s0;\
1531   if (EXPRVP(s0)) {\
1532     value = s0;\
1533   } else {\
1534     if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\
1535     sp[-1] = s0 = value = vp++;\
1536     if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
1537     s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\
1538   }\
1539 } while (0)
1540 
1541 #define POP2ALLOC1(arg1,arg2,value) do {\
1542   if (EXPRVP(s0)) { vp--; }\
1543   if (EXPRVP(s1)) { vp--; }\
1544   arg2 = s0;\
1545   arg1 = s1;\
1546   sp--;\
1547   if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\
1548   s1 = sp[-2];\
1549   sp[-1] = s0 = value = vp++;\
1550   if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
1551   s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\
1552 } while (0)
1553 
1554 #define INTEGER_ARITHMETIC_OPERATION_PLUS(x, y) ((x) + (y))
1555 #define FLOAT_ARITHMETIC_OPERATION_PLUS(x, y) ((double)(x) + (double)(y))
1556 #define INTEGER_ARITHMETIC_OPERATION_MINUS(x, y) ((x) - (y))
1557 #define FLOAT_ARITHMETIC_OPERATION_MINUS(x, y) ((double)(x) - (double)(y))
1558 #define INTEGER_ARITHMETIC_OPERATION_STAR(x, y) ((x) * (y))
1559 #define FLOAT_ARITHMETIC_OPERATION_STAR(x, y) ((double)(x) * (double)(y))
1560 #define INTEGER_ARITHMETIC_OPERATION_SLASH(x, y) ((x) / (y))
1561 #define FLOAT_ARITHMETIC_OPERATION_SLASH(x, y) ((double)(x) / (double)(y))
1562 #define INTEGER_ARITHMETIC_OPERATION_MOD(x, y) ((x) % (y))
1563 #define FLOAT_ARITHMETIC_OPERATION_MOD(x, y) (fmod((x), (y)))
1564 #define INTEGER_ARITHMETIC_OPERATION_SHIFTL(x, y) ((x) << (y))
1565 #define FLOAT_ARITHMETIC_OPERATION_SHIFTL(x, y)                         \
1566   ((long long int)(x) << (long long int)(y))
1567 #define INTEGER_ARITHMETIC_OPERATION_SHIFTR(x, y) ((x) >> (y))
1568 #define FLOAT_ARITHMETIC_OPERATION_SHIFTR(x, y)                         \
1569   ((long long int)(x) >> (long long int)(y))
1570 #define INTEGER8_ARITHMETIC_OPERATION_SHIFTRR(x, y)             \
1571   ((uint8_t)(x) >> (y))
1572 #define INTEGER16_ARITHMETIC_OPERATION_SHIFTRR(x, y)            \
1573   ((uint16_t)(x) >> (y))
1574 #define INTEGER32_ARITHMETIC_OPERATION_SHIFTRR(x, y)            \
1575   ((unsigned int)(x) >> (y))
1576 #define INTEGER64_ARITHMETIC_OPERATION_SHIFTRR(x, y)            \
1577   ((long long unsigned int)(x) >> (y))
1578 #define FLOAT_ARITHMETIC_OPERATION_SHIFTRR(x, y)                \
1579   ((long long unsigned int)(x) >> (long long unsigned int)(y))
1580 
1581 #define INTEGER_ARITHMETIC_OPERATION_BITWISE_OR(x, y) ((x) | (y))
1582 #define FLOAT_ARITHMETIC_OPERATION_BITWISE_OR(x, y)                \
1583   ((long long int)(x) | (long long int)(y))
1584 #define INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR(x, y) ((x) ^ (y))
1585 #define FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR(x, y)                \
1586   ((long long int)(x) ^ (long long int)(y))
1587 #define INTEGER_ARITHMETIC_OPERATION_BITWISE_AND(x, y) ((x) & (y))
1588 #define FLOAT_ARITHMETIC_OPERATION_BITWISE_AND(x, y)                \
1589   ((long long int)(x) & (long long int)(y))
1590 
1591 #define INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x))
1592 #define FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x))
1593 #define INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) (~(x))
1594 #define FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) \
1595   (~((long long int)(x)))
1596 
1597 #define TEXT_ARITHMETIC_OPERATION(operator) do {                        \
1598   long long int x_;                                                     \
1599   long long int y_;                                                     \
1600                                                                         \
1601   res->header.domain = GRN_DB_INT64;                                    \
1602                                                                         \
1603   GRN_INT64_SET(ctx, res, 0);                                           \
1604   grn_obj_cast(ctx, x, res, GRN_FALSE);                                 \
1605   x_ = GRN_INT64_VALUE(res);                                            \
1606                                                                         \
1607   GRN_INT64_SET(ctx, res, 0);                                           \
1608   grn_obj_cast(ctx, y, res, GRN_FALSE);                                 \
1609   y_ = GRN_INT64_VALUE(res);                                            \
1610                                                                         \
1611   GRN_INT64_SET(ctx, res, x_ operator y_);                              \
1612 } while (0)
1613 
1614 #define TEXT_UNARY_ARITHMETIC_OPERATION(unary_operator) do { \
1615   long long int x_;                                          \
1616                                                              \
1617   res->header.domain = GRN_DB_INT64;                         \
1618                                                              \
1619   GRN_INT64_SET(ctx, res, 0);                                \
1620   grn_obj_cast(ctx, x, res, GRN_FALSE);                      \
1621   x_ = GRN_INT64_VALUE(res);                                 \
1622                                                              \
1623   GRN_INT64_SET(ctx, res, unary_operator x_);                \
1624 } while (0)
1625 
1626 #define ARITHMETIC_OPERATION_NO_CHECK(y) do {} while (0)
1627 #define ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y) do {        \
1628   if ((long long int)y == 0) {                                  \
1629     ERR(GRN_INVALID_ARGUMENT, "divisor should not be 0");       \
1630     goto exit;                                                  \
1631   }                                                             \
1632 } while (0)
1633 
1634 
1635 #define NUMERIC_ARITHMETIC_OPERATION_DISPATCH(set, get, x_, y, res,     \
1636                                               integer_operation,        \
1637                                               float_operation,          \
1638                                               right_expression_check,   \
1639                                               invalid_type_error) do {  \
1640   switch (y->header.domain) {                                           \
1641   case GRN_DB_INT8 :                                                    \
1642     {                                                                   \
1643       int8_t y_;                                                        \
1644       y_ = GRN_INT8_VALUE(y);                                           \
1645       right_expression_check(y_);                                       \
1646       set(ctx, res, integer_operation(x_, y_));                         \
1647     }                                                                   \
1648     break;                                                              \
1649   case GRN_DB_UINT8 :                                                   \
1650     {                                                                   \
1651       uint8_t y_;                                                       \
1652       y_ = GRN_UINT8_VALUE(y);                                          \
1653       right_expression_check(y_);                                       \
1654       set(ctx, res, integer_operation(x_, y_));                         \
1655     }                                                                   \
1656     break;                                                              \
1657   case GRN_DB_INT16 :                                                   \
1658     {                                                                   \
1659       int16_t y_;                                                       \
1660       y_ = GRN_INT16_VALUE(y);                                          \
1661       right_expression_check(y_);                                       \
1662       set(ctx, res, integer_operation(x_, y_));                         \
1663     }                                                                   \
1664     break;                                                              \
1665   case GRN_DB_UINT16 :                                                  \
1666     {                                                                   \
1667       uint16_t y_;                                                      \
1668       y_ = GRN_UINT16_VALUE(y);                                         \
1669       right_expression_check(y_);                                       \
1670       set(ctx, res, integer_operation(x_, y_));                         \
1671     }                                                                   \
1672     break;                                                              \
1673   case GRN_DB_INT32 :                                                   \
1674     {                                                                   \
1675       int y_;                                                           \
1676       y_ = GRN_INT32_VALUE(y);                                          \
1677       right_expression_check(y_);                                       \
1678       set(ctx, res, integer_operation(x_, y_));                         \
1679     }                                                                   \
1680     break;                                                              \
1681   case GRN_DB_UINT32 :                                                  \
1682     {                                                                   \
1683       unsigned int y_;                                                  \
1684       y_ = GRN_UINT32_VALUE(y);                                         \
1685       right_expression_check(y_);                                       \
1686       set(ctx, res, integer_operation(x_, y_));                         \
1687     }                                                                   \
1688     break;                                                              \
1689   case GRN_DB_TIME :                                                    \
1690     {                                                                   \
1691       long long int y_;                                                 \
1692       y_ = GRN_TIME_VALUE(y);                                           \
1693       right_expression_check(y_);                                       \
1694       set(ctx, res, integer_operation(x_, y_));                         \
1695     }                                                                   \
1696     break;                                                              \
1697   case GRN_DB_INT64 :                                                   \
1698     {                                                                   \
1699       long long int y_;                                                 \
1700       y_ = GRN_INT64_VALUE(y);                                          \
1701       right_expression_check(y_);                                       \
1702       set(ctx, res, integer_operation(x_, y_));                         \
1703     }                                                                   \
1704     break;                                                              \
1705   case GRN_DB_UINT64 :                                                  \
1706     {                                                                   \
1707       long long unsigned int y_;                                        \
1708       y_ = GRN_UINT64_VALUE(y);                                         \
1709       right_expression_check(y_);                                       \
1710       set(ctx, res, integer_operation(x_, y_));                         \
1711     }                                                                   \
1712     break;                                                              \
1713   case GRN_DB_FLOAT :                                                   \
1714     {                                                                   \
1715       double y_;                                                        \
1716       y_ = GRN_FLOAT_VALUE(y);                                          \
1717       right_expression_check(y_);                                       \
1718       res->header.domain = GRN_DB_FLOAT;                                \
1719       GRN_FLOAT_SET(ctx, res, float_operation(x_, y_));                 \
1720     }                                                                   \
1721     break;                                                              \
1722   case GRN_DB_SHORT_TEXT :                                              \
1723   case GRN_DB_TEXT :                                                    \
1724   case GRN_DB_LONG_TEXT :                                               \
1725     set(ctx, res, 0);                                                   \
1726     if (grn_obj_cast(ctx, y, res, GRN_FALSE)) {                         \
1727       ERR(GRN_INVALID_ARGUMENT,                                         \
1728           "not a numerical format: <%.*s>",                             \
1729           (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y));                     \
1730       goto exit;                                                        \
1731     }                                                                   \
1732     set(ctx, res, integer_operation(x_, get(res)));                     \
1733     break;                                                              \
1734   default :                                                             \
1735     invalid_type_error;                                                 \
1736     break;                                                              \
1737   }                                                                     \
1738 } while (0)
1739 
1740 
1741 #define ARITHMETIC_OPERATION_DISPATCH(x, y, res,                        \
1742                                       integer8_operation,               \
1743                                       integer16_operation,              \
1744                                       integer32_operation,              \
1745                                       integer64_operation,              \
1746                                       float_operation,                  \
1747                                       left_expression_check,            \
1748                                       right_expression_check,           \
1749                                       text_operation,                   \
1750                                       invalid_type_error) do {          \
1751   switch (x->header.domain) {                                           \
1752   case GRN_DB_INT8 :                                                    \
1753     {                                                                   \
1754       int8_t x_;                                                        \
1755       x_ = GRN_INT8_VALUE(x);                                           \
1756       left_expression_check(x_);                                        \
1757       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT8_SET,               \
1758                                             GRN_INT8_VALUE,             \
1759                                             x_, y, res,                 \
1760                                             integer8_operation,         \
1761                                             float_operation,            \
1762                                             right_expression_check,     \
1763                                             invalid_type_error);        \
1764     }                                                                   \
1765     break;                                                              \
1766   case GRN_DB_UINT8 :                                                   \
1767     {                                                                   \
1768       uint8_t x_;                                                       \
1769       x_ = GRN_UINT8_VALUE(x);                                          \
1770       left_expression_check(x_);                                        \
1771       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT8_SET,              \
1772                                             GRN_UINT8_VALUE,            \
1773                                             x_, y, res,                 \
1774                                             integer8_operation,         \
1775                                             float_operation,            \
1776                                             right_expression_check,     \
1777                                             invalid_type_error);        \
1778     }                                                                   \
1779     break;                                                              \
1780   case GRN_DB_INT16 :                                                   \
1781     {                                                                   \
1782       int16_t x_;                                                       \
1783       x_ = GRN_INT16_VALUE(x);                                          \
1784       left_expression_check(x_);                                        \
1785       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT16_SET,              \
1786                                             GRN_INT16_VALUE,            \
1787                                             x_, y, res,                 \
1788                                             integer16_operation,        \
1789                                             float_operation,            \
1790                                             right_expression_check,     \
1791                                             invalid_type_error);        \
1792     }                                                                   \
1793     break;                                                              \
1794   case GRN_DB_UINT16 :                                                  \
1795     {                                                                   \
1796       uint16_t x_;                                                      \
1797       x_ = GRN_UINT16_VALUE(x);                                         \
1798       left_expression_check(x_);                                        \
1799       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT16_SET,             \
1800                                             GRN_UINT16_VALUE,           \
1801                                             x_, y, res,                 \
1802                                             integer16_operation,        \
1803                                             float_operation,            \
1804                                             right_expression_check,     \
1805                                             invalid_type_error);        \
1806     }                                                                   \
1807     break;                                                              \
1808   case GRN_DB_INT32 :                                                   \
1809     {                                                                   \
1810       int x_;                                                           \
1811       x_ = GRN_INT32_VALUE(x);                                          \
1812       left_expression_check(x_);                                        \
1813       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT32_SET,              \
1814                                             GRN_INT32_VALUE,            \
1815                                             x_, y, res,                 \
1816                                             integer32_operation,        \
1817                                             float_operation,            \
1818                                             right_expression_check,     \
1819                                             invalid_type_error);        \
1820     }                                                                   \
1821     break;                                                              \
1822   case GRN_DB_UINT32 :                                                  \
1823     {                                                                   \
1824       unsigned int x_;                                                  \
1825       x_ = GRN_UINT32_VALUE(x);                                         \
1826       left_expression_check(x_);                                        \
1827       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT32_SET,             \
1828                                             GRN_UINT32_VALUE,           \
1829                                             x_, y, res,                 \
1830                                             integer32_operation,        \
1831                                             float_operation,            \
1832                                             right_expression_check,     \
1833                                             invalid_type_error);        \
1834     }                                                                   \
1835     break;                                                              \
1836   case GRN_DB_INT64 :                                                   \
1837     {                                                                   \
1838       long long int x_;                                                 \
1839       x_ = GRN_INT64_VALUE(x);                                          \
1840       left_expression_check(x_);                                        \
1841       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT64_SET,              \
1842                                             GRN_INT64_VALUE,            \
1843                                             x_, y, res,                 \
1844                                             integer64_operation,        \
1845                                             float_operation,            \
1846                                             right_expression_check,     \
1847                                             invalid_type_error);        \
1848     }                                                                   \
1849     break;                                                              \
1850   case GRN_DB_TIME :                                                    \
1851     {                                                                   \
1852       long long int x_;                                                 \
1853       x_ = GRN_TIME_VALUE(x);                                           \
1854       left_expression_check(x_);                                        \
1855       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_TIME_SET,               \
1856                                             GRN_TIME_VALUE,             \
1857                                             x_, y, res,                 \
1858                                             integer64_operation,        \
1859                                             float_operation,            \
1860                                             right_expression_check,     \
1861                                             invalid_type_error);        \
1862     }                                                                   \
1863     break;                                                              \
1864   case GRN_DB_UINT64 :                                                  \
1865     {                                                                   \
1866       long long unsigned int x_;                                        \
1867       x_ = GRN_UINT64_VALUE(x);                                         \
1868       left_expression_check(x_);                                        \
1869       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT64_SET,             \
1870                                             GRN_UINT64_VALUE,           \
1871                                             x_, y, res,                 \
1872                                             integer64_operation,        \
1873                                             float_operation,            \
1874                                             right_expression_check,     \
1875                                             invalid_type_error);        \
1876     }                                                                   \
1877     break;                                                              \
1878   case GRN_DB_FLOAT :                                                   \
1879     {                                                                   \
1880       double x_;                                                        \
1881       x_ = GRN_FLOAT_VALUE(x);                                          \
1882       left_expression_check(x_);                                        \
1883       NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_FLOAT_SET,              \
1884                                             GRN_FLOAT_VALUE,            \
1885                                             x_, y, res,                 \
1886                                             float_operation,            \
1887                                             float_operation,            \
1888                                             right_expression_check,     \
1889                                             invalid_type_error);        \
1890     }                                                                   \
1891     break;                                                              \
1892   case GRN_DB_SHORT_TEXT :                                              \
1893   case GRN_DB_TEXT :                                                    \
1894   case GRN_DB_LONG_TEXT :                                               \
1895     text_operation;                                                     \
1896     break;                                                              \
1897   default:                                                              \
1898     invalid_type_error;                                                 \
1899     break;                                                              \
1900   }                                                                     \
1901   code++;                                                               \
1902 } while (0)
1903 
1904 #define ARITHMETIC_BINARY_OPERATION_DISPATCH(operator,                  \
1905                                              integer8_operation,        \
1906                                              integer16_operation,       \
1907                                              integer32_operation,       \
1908                                              integer64_operation,       \
1909                                              float_operation,           \
1910                                              left_expression_check,     \
1911                                              right_expression_check,    \
1912                                              text_operation,            \
1913                                              invalid_type_error) do {   \
1914   grn_obj *x, *y;                                                       \
1915                                                                         \
1916   POP2ALLOC1(x, y, res);                                                \
1917   if (x->header.type == GRN_VECTOR || y->header.type == GRN_VECTOR) {   \
1918     grn_obj inspected_x;                                                \
1919     grn_obj inspected_y;                                                \
1920     GRN_TEXT_INIT(&inspected_x, 0);                                     \
1921     GRN_TEXT_INIT(&inspected_y, 0);                                     \
1922     grn_inspect(ctx, &inspected_x, x);                                  \
1923     grn_inspect(ctx, &inspected_y, y);                                  \
1924     ERR(GRN_INVALID_ARGUMENT,                                           \
1925         "<%s> doesn't support vector: <%.*s> %s <%.*s>",                \
1926         operator,                                                       \
1927         (int)GRN_TEXT_LEN(&inspected_x), GRN_TEXT_VALUE(&inspected_x),  \
1928         operator,                                                       \
1929         (int)GRN_TEXT_LEN(&inspected_y), GRN_TEXT_VALUE(&inspected_y)); \
1930     GRN_OBJ_FIN(ctx, &inspected_x);                                     \
1931     GRN_OBJ_FIN(ctx, &inspected_y);                                     \
1932     goto exit;                                                          \
1933   }                                                                     \
1934   if (y != res) {                                                       \
1935     res->header.domain = x->header.domain;                              \
1936   }                                                                     \
1937   ARITHMETIC_OPERATION_DISPATCH(x, y, res,                              \
1938                                 integer8_operation,                     \
1939                                 integer16_operation,                    \
1940                                 integer32_operation,                    \
1941                                 integer64_operation,                    \
1942                                 float_operation,                        \
1943                                 left_expression_check,                  \
1944                                 right_expression_check,                 \
1945                                 text_operation,                         \
1946                                 invalid_type_error);                    \
1947   if (y == res) {                                                       \
1948     res->header.domain = x->header.domain;                              \
1949   }                                                                     \
1950 } while (0)
1951 
1952 #define SIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y)                   \
1953   ((y == -1) ? -(x) : (x) / (y))
1954 #define UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) ((x) / (y))
1955 #define FLOAT_DIVISION_OPERATION_SLASH(x, y) ((double)(x) / (double)(y))
1956 #define SIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((y == -1) ? 0 : (x) % (y))
1957 #define UNSIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((x) % (y))
1958 #define FLOAT_DIVISION_OPERATION_MOD(x, y) (fmod((x), (y)))
1959 
1960 #define DIVISION_OPERATION_DISPATCH_RIGHT(set, get, x_, y, res,         \
1961                                           signed_integer_operation,     \
1962                                           unsigned_integer_operation,   \
1963                                           float_operation) do {         \
1964   switch (y->header.domain) {                                           \
1965   case GRN_DB_INT8 :                                                    \
1966     {                                                                   \
1967       int y_;                                                           \
1968       y_ = GRN_INT8_VALUE(y);                                           \
1969       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
1970       set(ctx, res, signed_integer_operation(x_, y_));                  \
1971     }                                                                   \
1972     break;                                                              \
1973   case GRN_DB_UINT8 :                                                   \
1974     {                                                                   \
1975       int y_;                                                           \
1976       y_ = GRN_UINT8_VALUE(y);                                          \
1977       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
1978       set(ctx, res, unsigned_integer_operation(x_, y_));                \
1979     }                                                                   \
1980     break;                                                              \
1981   case GRN_DB_INT16 :                                                   \
1982     {                                                                   \
1983       int y_;                                                           \
1984       y_ = GRN_INT16_VALUE(y);                                          \
1985       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
1986       set(ctx, res, signed_integer_operation(x_, y_));                  \
1987     }                                                                   \
1988     break;                                                              \
1989   case GRN_DB_UINT16 :                                                  \
1990     {                                                                   \
1991       int y_;                                                           \
1992       y_ = GRN_UINT16_VALUE(y);                                         \
1993       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
1994       set(ctx, res, unsigned_integer_operation(x_, y_));                \
1995     }                                                                   \
1996     break;                                                              \
1997   case GRN_DB_INT32 :                                                   \
1998     {                                                                   \
1999       int y_;                                                           \
2000       y_ = GRN_INT32_VALUE(y);                                          \
2001       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
2002       set(ctx, res, signed_integer_operation(x_, y_));                  \
2003     }                                                                   \
2004     break;                                                              \
2005   case GRN_DB_UINT32 :                                                  \
2006     {                                                                   \
2007       unsigned int y_;                                                  \
2008       y_ = GRN_UINT32_VALUE(y);                                         \
2009       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
2010       set(ctx, res, unsigned_integer_operation(x_, y_));                \
2011     }                                                                   \
2012     break;                                                              \
2013   case GRN_DB_TIME :                                                    \
2014     {                                                                   \
2015       long long int y_;                                                 \
2016       y_ = GRN_TIME_VALUE(y);                                           \
2017       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
2018       set(ctx, res, signed_integer_operation(x_, y_));                  \
2019     }                                                                   \
2020     break;                                                              \
2021   case GRN_DB_INT64 :                                                   \
2022     {                                                                   \
2023       long long int y_;                                                 \
2024       y_ = GRN_INT64_VALUE(y);                                          \
2025       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
2026       set(ctx, res, signed_integer_operation(x_, y_));                  \
2027     }                                                                   \
2028     break;                                                              \
2029   case GRN_DB_UINT64 :                                                  \
2030     {                                                                   \
2031       long long unsigned int y_;                                        \
2032       y_ = GRN_UINT64_VALUE(y);                                         \
2033       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
2034       set(ctx, res, unsigned_integer_operation(x_, y_));                \
2035     }                                                                   \
2036     break;                                                              \
2037   case GRN_DB_FLOAT :                                                   \
2038     {                                                                   \
2039       double y_;                                                        \
2040       y_ = GRN_FLOAT_VALUE(y);                                          \
2041       ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
2042       res->header.domain = GRN_DB_FLOAT;                                \
2043       GRN_FLOAT_SET(ctx, res, float_operation(x_, y_));                 \
2044     }                                                                   \
2045     break;                                                              \
2046   case GRN_DB_SHORT_TEXT :                                              \
2047   case GRN_DB_TEXT :                                                    \
2048   case GRN_DB_LONG_TEXT :                                               \
2049     set(ctx, res, 0);                                                   \
2050     if (grn_obj_cast(ctx, y, res, GRN_FALSE)) {                         \
2051       ERR(GRN_INVALID_ARGUMENT,                                         \
2052           "not a numerical format: <%.*s>",                             \
2053           (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y));                     \
2054       goto exit;                                                        \
2055     }                                                                   \
2056     /* The following "+ 0" is needed to suppress warnings that say */   \
2057     /* comparison is always false due to limited range of data type */  \
2058     set(ctx, res, signed_integer_operation(x_, (get(res) + 0)));        \
2059     break;                                                              \
2060   default :                                                             \
2061     break;                                                              \
2062   }                                                                     \
2063 } while (0)
2064 
2065 #define DIVISION_OPERATION_DISPATCH_LEFT(x, y, res,                     \
2066                                          signed_integer_operation,      \
2067                                          unsigned_integer_operation,    \
2068                                          float_operation,               \
2069                                          invalid_type_error) do {       \
2070   switch (x->header.domain) {                                           \
2071   case GRN_DB_INT8 :                                                    \
2072     {                                                                   \
2073       int x_;                                                           \
2074       x_ = GRN_INT8_VALUE(x);                                           \
2075       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT8_SET,                   \
2076                                         GRN_INT8_VALUE,                 \
2077                                         x_, y, res,                     \
2078                                         signed_integer_operation,       \
2079                                         unsigned_integer_operation,     \
2080                                         float_operation);               \
2081     }                                                                   \
2082     break;                                                              \
2083   case GRN_DB_UINT8 :                                                   \
2084     {                                                                   \
2085       int x_;                                                           \
2086       x_ = GRN_UINT8_VALUE(x);                                          \
2087       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT8_SET,                  \
2088                                         (int)GRN_UINT8_VALUE,           \
2089                                         x_, y, res,                     \
2090                                         signed_integer_operation,       \
2091                                         unsigned_integer_operation,     \
2092                                         float_operation);               \
2093     }                                                                   \
2094     break;                                                              \
2095   case GRN_DB_INT16 :                                                   \
2096     {                                                                   \
2097       int x_;                                                           \
2098       x_ = GRN_INT16_VALUE(x);                                          \
2099       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT16_SET,                  \
2100                                         GRN_INT16_VALUE,                \
2101                                         x_, y, res,                     \
2102                                         signed_integer_operation,       \
2103                                         unsigned_integer_operation,     \
2104                                         float_operation);               \
2105     }                                                                   \
2106     break;                                                              \
2107   case GRN_DB_UINT16 :                                                  \
2108     {                                                                   \
2109       int x_;                                                           \
2110       x_ = GRN_UINT16_VALUE(x);                                         \
2111       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT16_SET,                 \
2112                                         (int)GRN_UINT16_VALUE,          \
2113                                         x_, y, res,                     \
2114                                         signed_integer_operation,       \
2115                                         unsigned_integer_operation,     \
2116                                         float_operation);               \
2117     }                                                                   \
2118     break;                                                              \
2119   case GRN_DB_INT32 :                                                   \
2120     {                                                                   \
2121       int x_;                                                           \
2122       x_ = GRN_INT32_VALUE(x);                                          \
2123       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT32_SET,                  \
2124                                         GRN_INT32_VALUE,                \
2125                                         x_, y, res,                     \
2126                                         signed_integer_operation,       \
2127                                         unsigned_integer_operation,     \
2128                                         float_operation);               \
2129     }                                                                   \
2130     break;                                                              \
2131   case GRN_DB_UINT32 :                                                  \
2132     {                                                                   \
2133       unsigned int x_;                                                  \
2134       x_ = GRN_UINT32_VALUE(x);                                         \
2135       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT32_SET,                 \
2136                                         GRN_UINT32_VALUE,               \
2137                                         x_, y, res,                     \
2138                                         unsigned_integer_operation,     \
2139                                         unsigned_integer_operation,     \
2140                                         float_operation);               \
2141     }                                                                   \
2142     break;                                                              \
2143   case GRN_DB_INT64 :                                                   \
2144     {                                                                   \
2145       long long int x_;                                                 \
2146       x_ = GRN_INT64_VALUE(x);                                          \
2147       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT64_SET,                  \
2148                                         GRN_INT64_VALUE,                \
2149                                         x_, y, res,                     \
2150                                         signed_integer_operation,       \
2151                                         unsigned_integer_operation,     \
2152                                         float_operation);               \
2153     }                                                                   \
2154     break;                                                              \
2155   case GRN_DB_TIME :                                                    \
2156     {                                                                   \
2157       long long int x_;                                                 \
2158       x_ = GRN_TIME_VALUE(x);                                           \
2159       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_TIME_SET,                   \
2160                                         GRN_TIME_VALUE,                 \
2161                                         x_, y, res,                     \
2162                                         signed_integer_operation,       \
2163                                         unsigned_integer_operation,     \
2164                                         float_operation);               \
2165     }                                                                   \
2166     break;                                                              \
2167   case GRN_DB_UINT64 :                                                  \
2168     {                                                                   \
2169       long long unsigned int x_;                                        \
2170       x_ = GRN_UINT64_VALUE(x);                                         \
2171       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT64_SET,                 \
2172                                         GRN_UINT64_VALUE,               \
2173                                         x_, y, res,                     \
2174                                         unsigned_integer_operation,     \
2175                                         unsigned_integer_operation,     \
2176                                         float_operation);               \
2177     }                                                                   \
2178     break;                                                              \
2179   case GRN_DB_FLOAT :                                                   \
2180     {                                                                   \
2181       double x_;                                                        \
2182       x_ = GRN_FLOAT_VALUE(x);                                          \
2183       DIVISION_OPERATION_DISPATCH_RIGHT(GRN_FLOAT_SET,                  \
2184                                         GRN_FLOAT_VALUE,                \
2185                                         x_, y, res,                     \
2186                                         float_operation,                \
2187                                         float_operation,                \
2188                                         float_operation);               \
2189     }                                                                   \
2190     break;                                                              \
2191   case GRN_DB_SHORT_TEXT :                                              \
2192   case GRN_DB_TEXT :                                                    \
2193   case GRN_DB_LONG_TEXT :                                               \
2194     invalid_type_error;                                                 \
2195     break;                                                              \
2196   default:                                                              \
2197     break;                                                              \
2198   }                                                                     \
2199   code++;                                                               \
2200 } while (0)
2201 
2202 #define DIVISION_OPERATION_DISPATCH(signed_integer_operation,           \
2203                                     unsigned_integer_operation,         \
2204                                     float_operation,                    \
2205                                     invalid_type_error) do {            \
2206   grn_obj *x, *y;                                                       \
2207                                                                         \
2208   POP2ALLOC1(x, y, res);                                                \
2209   if (y != res) {                                                       \
2210     res->header.domain = x->header.domain;                              \
2211   }                                                                     \
2212   DIVISION_OPERATION_DISPATCH_LEFT(x, y, res,                           \
2213                                    signed_integer_operation,            \
2214                                    unsigned_integer_operation,          \
2215                                    float_operation,                     \
2216                                    invalid_type_error);                 \
2217   if (y == res) {                                                       \
2218     res->header.domain = x->header.domain;                              \
2219   }                                                                     \
2220 } while (0)
2221 
2222 #define ARITHMETIC_UNARY_OPERATION_DISPATCH(integer_operation,          \
2223                                             float_operation,            \
2224                                             left_expression_check,      \
2225                                             right_expression_check,     \
2226                                             text_operation,             \
2227                                             invalid_type_error) do {    \
2228   grn_obj *x;                                                           \
2229   POP1ALLOC1(x, res);                                                   \
2230   res->header.domain = x->header.domain;                                \
2231   switch (x->header.domain) {                                           \
2232   case GRN_DB_INT8 :                                                    \
2233     {                                                                   \
2234       int8_t x_;                                                        \
2235       x_ = GRN_INT8_VALUE(x);                                           \
2236       left_expression_check(x_);                                        \
2237       GRN_INT8_SET(ctx, res, integer_operation(x_));                    \
2238     }                                                                   \
2239     break;                                                              \
2240   case GRN_DB_UINT8 :                                                   \
2241     {                                                                   \
2242       int16_t x_;                                                       \
2243       x_ = GRN_UINT8_VALUE(x);                                          \
2244       left_expression_check(x_);                                        \
2245       GRN_INT16_SET(ctx, res, integer_operation(x_));                   \
2246       res->header.domain = GRN_DB_INT16;                                \
2247     }                                                                   \
2248     break;                                                              \
2249   case GRN_DB_INT16 :                                                   \
2250     {                                                                   \
2251       int16_t x_;                                                       \
2252       x_ = GRN_INT16_VALUE(x);                                          \
2253       left_expression_check(x_);                                        \
2254       GRN_INT16_SET(ctx, res, integer_operation(x_));                   \
2255     }                                                                   \
2256     break;                                                              \
2257   case GRN_DB_UINT16 :                                                  \
2258     {                                                                   \
2259       int x_;                                                           \
2260       x_ = GRN_UINT16_VALUE(x);                                         \
2261       left_expression_check(x_);                                        \
2262       GRN_INT32_SET(ctx, res, integer_operation(x_));                   \
2263       res->header.domain = GRN_DB_INT32;                                \
2264     }                                                                   \
2265     break;                                                              \
2266   case GRN_DB_INT32 :                                                   \
2267     {                                                                   \
2268       int x_;                                                           \
2269       x_ = GRN_INT32_VALUE(x);                                          \
2270       left_expression_check(x_);                                        \
2271       GRN_INT32_SET(ctx, res, integer_operation(x_));                   \
2272     }                                                                   \
2273     break;                                                              \
2274   case GRN_DB_UINT32 :                                                  \
2275     {                                                                   \
2276       long long int x_;                                                 \
2277       x_ = GRN_UINT32_VALUE(x);                                         \
2278       left_expression_check(x_);                                        \
2279       GRN_INT64_SET(ctx, res, integer_operation(x_));                   \
2280       res->header.domain = GRN_DB_INT64;                                \
2281     }                                                                   \
2282     break;                                                              \
2283   case GRN_DB_INT64 :                                                   \
2284     {                                                                   \
2285       long long int x_;                                                 \
2286       x_ = GRN_INT64_VALUE(x);                                          \
2287       left_expression_check(x_);                                        \
2288       GRN_INT64_SET(ctx, res, integer_operation(x_));                   \
2289     }                                                                   \
2290     break;                                                              \
2291   case GRN_DB_TIME :                                                    \
2292     {                                                                   \
2293       long long int x_;                                                 \
2294       x_ = GRN_TIME_VALUE(x);                                           \
2295       left_expression_check(x_);                                        \
2296       GRN_TIME_SET(ctx, res, integer_operation(x_));                    \
2297     }                                                                   \
2298     break;                                                              \
2299   case GRN_DB_UINT64 :                                                  \
2300     {                                                                   \
2301       long long unsigned int x_;                                        \
2302       x_ = GRN_UINT64_VALUE(x);                                         \
2303       left_expression_check(x_);                                        \
2304       if (x_ > (long long unsigned int)INT64_MAX) {                     \
2305         ERR(GRN_INVALID_ARGUMENT,                                       \
2306             "too large UInt64 value to inverse sign: "                  \
2307             "<%" GRN_FMT_LLU ">",                                       \
2308             x_);                                                        \
2309         goto exit;                                                      \
2310       } else {                                                          \
2311         long long int signed_x_;                                        \
2312         signed_x_ = x_;                                                 \
2313         GRN_INT64_SET(ctx, res, integer_operation(signed_x_));          \
2314         res->header.domain = GRN_DB_INT64;                              \
2315       }                                                                 \
2316     }                                                                   \
2317     break;                                                              \
2318   case GRN_DB_FLOAT :                                                   \
2319     {                                                                   \
2320       double x_;                                                        \
2321       x_ = GRN_FLOAT_VALUE(x);                                          \
2322       left_expression_check(x_);                                        \
2323       GRN_FLOAT_SET(ctx, res, float_operation(x_));                     \
2324     }                                                                   \
2325     break;                                                              \
2326   case GRN_DB_SHORT_TEXT :                                              \
2327   case GRN_DB_TEXT :                                                    \
2328   case GRN_DB_LONG_TEXT :                                               \
2329     text_operation;                                                     \
2330     break;                                                              \
2331   default:                                                              \
2332     invalid_type_error;                                                 \
2333     break;                                                              \
2334   }                                                                     \
2335   code++;                                                               \
2336 } while (0)
2337 
2338 #define EXEC_OPERATE(operate_sentence, assign_sentence)   \
2339   operate_sentence                                        \
2340   assign_sentence
2341 
2342 #define EXEC_OPERATE_POST(operate_sentence, assign_sentence)    \
2343   assign_sentence                                               \
2344   operate_sentence
2345 
2346 #define UNARY_OPERATE_AND_ASSIGN_DISPATCH(exec_operate, delta,          \
2347                                           set_flags) do {               \
2348   grn_obj *var, *col, value;                                            \
2349   grn_id rid;                                                           \
2350                                                                         \
2351   POP1ALLOC1(var, res);                                                 \
2352   if (var->header.type != GRN_PTR) {                                    \
2353     ERR(GRN_INVALID_ARGUMENT, "invalid variable type: 0x%0x",           \
2354         var->header.type);                                              \
2355     goto exit;                                                          \
2356   }                                                                     \
2357   if (GRN_BULK_VSIZE(var) != (sizeof(grn_obj *) + sizeof(grn_id))) {    \
2358     ERR(GRN_INVALID_ARGUMENT,                                           \
2359         "invalid variable size: "                                       \
2360         "expected: %" GRN_FMT_SIZE                                      \
2361         "actual: %" GRN_FMT_SIZE,                                       \
2362         (sizeof(grn_obj *) + sizeof(grn_id)), GRN_BULK_VSIZE(var));     \
2363     goto exit;                                                          \
2364   }                                                                     \
2365   col = GRN_PTR_VALUE(var);                                             \
2366   rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *));            \
2367   res->header.type = GRN_VOID;                                          \
2368   res->header.domain = DB_OBJ(col)->range;                              \
2369   switch (DB_OBJ(col)->range) {                                         \
2370   case GRN_DB_INT32 :                                                   \
2371     GRN_INT32_INIT(&value, 0);                                          \
2372     GRN_INT32_SET(ctx, &value, delta);                                  \
2373     break;                                                              \
2374   case GRN_DB_UINT32 :                                                  \
2375     GRN_UINT32_INIT(&value, 0);                                         \
2376     GRN_UINT32_SET(ctx, &value, delta);                                 \
2377     break;                                                              \
2378   case GRN_DB_INT64 :                                                   \
2379     GRN_INT64_INIT(&value, 0);                                          \
2380     GRN_INT64_SET(ctx, &value, delta);                                  \
2381     break;                                                              \
2382   case GRN_DB_UINT64 :                                                  \
2383     GRN_UINT64_INIT(&value, 0);                                         \
2384     GRN_UINT64_SET(ctx, &value, delta);                                 \
2385     break;                                                              \
2386   case GRN_DB_FLOAT :                                                   \
2387     GRN_FLOAT_INIT(&value, 0);                                          \
2388     GRN_FLOAT_SET(ctx, &value, delta);                                  \
2389     break;                                                              \
2390   case GRN_DB_TIME :                                                    \
2391     GRN_TIME_INIT(&value, 0);                                           \
2392     GRN_TIME_SET(ctx, &value, GRN_TIME_PACK(delta, 0));                 \
2393     break;                                                              \
2394   default:                                                              \
2395     ERR(GRN_INVALID_ARGUMENT,                                           \
2396         "invalid increment target type: %d "                            \
2397         "(FIXME: type name is needed)", DB_OBJ(col)->range);            \
2398     goto exit;                                                          \
2399     break;                                                              \
2400   }                                                                     \
2401   exec_operate(grn_obj_set_value(ctx, col, rid, &value, set_flags);,    \
2402                grn_obj_get_value(ctx, col, rid, res););                 \
2403   code++;                                                               \
2404 } while (0)
2405 
2406 #define ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(integer8_operation,    \
2407                                                  integer16_operation,   \
2408                                                  integer32_operation,   \
2409                                                  integer64_operation,   \
2410                                                  float_operation,       \
2411                                                  left_expression_check, \
2412                                                  right_expression_check,\
2413                                                  text_operation) do {   \
2414   grn_obj *value, *var, *res;                                           \
2415   if (code->value) {                                                    \
2416     value = code->value;                                                \
2417     POP1ALLOC1(var, res);                                               \
2418   } else {                                                              \
2419     POP2ALLOC1(var, value, res);                                        \
2420   }                                                                     \
2421   if (var->header.type == GRN_PTR &&                                    \
2422       GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) {    \
2423     grn_obj *col = GRN_PTR_VALUE(var);                                  \
2424     grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *));   \
2425     grn_obj variable_value, casted_value;                               \
2426     grn_id domain;                                                      \
2427                                                                         \
2428     value = GRN_OBJ_RESOLVE(ctx, value);                                \
2429                                                                         \
2430     domain = grn_obj_get_range(ctx, col);                               \
2431     GRN_OBJ_INIT(&variable_value, GRN_BULK, 0, domain);                 \
2432     grn_obj_get_value(ctx, col, rid, &variable_value);                  \
2433                                                                         \
2434     GRN_OBJ_INIT(&casted_value, GRN_BULK, 0, domain);                   \
2435     if (grn_obj_cast(ctx, value, &casted_value, GRN_FALSE)) {           \
2436       ERR(GRN_INVALID_ARGUMENT, "invalid value: string");               \
2437       GRN_OBJ_FIN(ctx, &variable_value);                                \
2438       GRN_OBJ_FIN(ctx, &casted_value);                                  \
2439       POP1(res);                                                        \
2440       goto exit;                                                        \
2441     }                                                                   \
2442     grn_obj_reinit(ctx, res, domain, 0);                                \
2443     ARITHMETIC_OPERATION_DISPATCH((&variable_value), (&casted_value),   \
2444                                   res,                                  \
2445                                   integer8_operation,                   \
2446                                   integer16_operation,                  \
2447                                   integer32_operation,                  \
2448                                   integer64_operation,                  \
2449                                   float_operation,                      \
2450                                   left_expression_check,                \
2451                                   right_expression_check,               \
2452                                   text_operation,);                     \
2453     grn_obj_set_value(ctx, col, rid, res, GRN_OBJ_SET);                 \
2454     GRN_OBJ_FIN(ctx, (&variable_value));                                \
2455     GRN_OBJ_FIN(ctx, (&casted_value));                                  \
2456   } else {                                                              \
2457     ERR(GRN_INVALID_ARGUMENT, "left hand expression isn't column.");    \
2458     POP1(res);                                                          \
2459   }                                                                     \
2460 } while (0)
2461 
2462 inline static void
grn_expr_exec_get_member_vector(grn_ctx * ctx,grn_obj * expr,grn_obj * column_and_record_id,grn_obj * index,grn_obj * result)2463 grn_expr_exec_get_member_vector(grn_ctx *ctx,
2464                                 grn_obj *expr,
2465                                 grn_obj *column_and_record_id,
2466                                 grn_obj *index,
2467                                 grn_obj *result)
2468 {
2469   grn_obj *column;
2470   grn_id record_id;
2471   grn_obj values;
2472   int i;
2473 
2474   column = GRN_PTR_VALUE(column_and_record_id);
2475   record_id = *((grn_id *)(&(GRN_PTR_VALUE_AT(column_and_record_id, 1))));
2476   GRN_TEXT_INIT(&values, 0);
2477   grn_obj_get_value(ctx, column, record_id, &values);
2478 
2479   i = GRN_UINT32_VALUE(index);
2480   if (values.header.type == GRN_UVECTOR) {
2481     int n_elements = 0;
2482     grn_obj *range;
2483     grn_id range_id = DB_OBJ(column)->range;
2484 
2485     grn_obj_reinit(ctx, result, range_id, 0);
2486     range = grn_ctx_at(ctx, range_id);
2487     if (range) {
2488       switch (range->header.type) {
2489       case GRN_TYPE :
2490         n_elements = GRN_BULK_VSIZE(&values) / grn_type_size(ctx, range);
2491         break;
2492       case GRN_TABLE_HASH_KEY :
2493       case GRN_TABLE_PAT_KEY :
2494       case GRN_TABLE_DAT_KEY :
2495       case GRN_TABLE_NO_KEY :
2496         n_elements = GRN_BULK_VSIZE(&values) / sizeof(grn_id);
2497         break;
2498       }
2499     }
2500     if (n_elements > i) {
2501 #define GET_UVECTOR_ELEMENT_AS(type) do {                               \
2502         GRN_ ## type ## _SET(ctx,                                       \
2503                              result,                                    \
2504                              GRN_ ## type ## _VALUE_AT(&values, i));    \
2505       } while (GRN_FALSE)
2506       switch (values.header.domain) {
2507       case GRN_DB_BOOL :
2508         GET_UVECTOR_ELEMENT_AS(BOOL);
2509         break;
2510       case GRN_DB_INT8 :
2511         GET_UVECTOR_ELEMENT_AS(INT8);
2512         break;
2513       case GRN_DB_UINT8 :
2514         GET_UVECTOR_ELEMENT_AS(UINT8);
2515         break;
2516       case GRN_DB_INT16 :
2517         GET_UVECTOR_ELEMENT_AS(INT16);
2518         break;
2519       case GRN_DB_UINT16 :
2520         GET_UVECTOR_ELEMENT_AS(UINT16);
2521         break;
2522       case GRN_DB_INT32 :
2523         GET_UVECTOR_ELEMENT_AS(INT32);
2524         break;
2525       case GRN_DB_UINT32 :
2526         GET_UVECTOR_ELEMENT_AS(UINT32);
2527         break;
2528       case GRN_DB_INT64 :
2529         GET_UVECTOR_ELEMENT_AS(INT64);
2530         break;
2531       case GRN_DB_UINT64 :
2532         GET_UVECTOR_ELEMENT_AS(UINT64);
2533         break;
2534       case GRN_DB_FLOAT :
2535         GET_UVECTOR_ELEMENT_AS(FLOAT);
2536         break;
2537       case GRN_DB_TIME :
2538         GET_UVECTOR_ELEMENT_AS(TIME);
2539         break;
2540       default :
2541         GET_UVECTOR_ELEMENT_AS(RECORD);
2542         break;
2543       }
2544 #undef GET_UVECTOR_ELEMENT_AS
2545     }
2546   } else {
2547     if (values.u.v.n_sections > i) {
2548       const char *content;
2549       unsigned int content_length;
2550       grn_id domain;
2551 
2552       content_length = grn_vector_get_element(ctx, &values, i,
2553                                               &content, NULL, &domain);
2554       grn_obj_reinit(ctx, result, domain, 0);
2555       grn_bulk_write(ctx, result, content, content_length);
2556     }
2557   }
2558 
2559   GRN_OBJ_FIN(ctx, &values);
2560 }
2561 
2562 inline static void
grn_expr_exec_get_member_table(grn_ctx * ctx,grn_obj * expr,grn_obj * table,grn_obj * key,grn_obj * result)2563 grn_expr_exec_get_member_table(grn_ctx *ctx,
2564                                grn_obj *expr,
2565                                grn_obj *table,
2566                                grn_obj *key,
2567                                grn_obj *result)
2568 {
2569   grn_id id;
2570 
2571   if (table->header.domain == key->header.domain) {
2572     id = grn_table_get(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key));
2573   } else {
2574     grn_obj casted_key;
2575     GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain);
2576     if (grn_obj_cast(ctx, key, &casted_key, GRN_FALSE) == GRN_SUCCESS) {
2577       id = grn_table_get(ctx, table,
2578                          GRN_BULK_HEAD(&casted_key),
2579                          GRN_BULK_VSIZE(&casted_key));
2580     } else {
2581       id = GRN_ID_NIL;
2582     }
2583     GRN_OBJ_FIN(ctx, &casted_key);
2584   }
2585 
2586   grn_obj_reinit(ctx, result, DB_OBJ(table)->id, 0);
2587   GRN_RECORD_SET(ctx, result, id);
2588 }
2589 
2590 static inline grn_bool
grn_expr_exec_is_simple_expr(grn_ctx * ctx,grn_obj * expr)2591 grn_expr_exec_is_simple_expr(grn_ctx *ctx, grn_obj *expr)
2592 {
2593   grn_expr *e = (grn_expr *)expr;
2594 
2595   if (expr->header.type != GRN_EXPR) {
2596     return GRN_FALSE;
2597   }
2598 
2599   if (e->codes_curr != 1) {
2600     return GRN_FALSE;
2601   }
2602 
2603   switch (e->codes[0].op) {
2604   case GRN_OP_PUSH :
2605     return GRN_TRUE;
2606   default :
2607     return GRN_FALSE;
2608   }
2609 }
2610 
2611 static inline grn_obj *
grn_expr_exec_simple(grn_ctx * ctx,grn_obj * expr)2612 grn_expr_exec_simple(grn_ctx *ctx, grn_obj *expr)
2613 {
2614   grn_expr *e = (grn_expr *)expr;
2615 
2616   return e->codes[0].value;
2617 }
2618 
2619 grn_obj *
grn_expr_exec(grn_ctx * ctx,grn_obj * expr,int nargs)2620 grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs)
2621 {
2622   grn_obj *val = NULL;
2623   uint32_t stack_curr = ctx->impl->stack_curr;
2624   GRN_API_ENTER;
2625   if (grn_expr_exec_is_simple_expr(ctx, expr)) {
2626     val = grn_expr_exec_simple(ctx, expr);
2627     GRN_API_RETURN(val);
2628   }
2629   if (expr->header.type == GRN_PROC) {
2630     grn_proc *proc = (grn_proc *)expr;
2631     if (proc->type == GRN_PROC_COMMAND) {
2632       grn_command_input *input;
2633       input = grn_command_input_open(ctx, expr);
2634       grn_command_run(ctx, expr, input);
2635       grn_command_input_close(ctx, input);
2636       GRN_API_RETURN(NULL);
2637     } else {
2638       grn_proc_call(ctx, expr, nargs, expr);
2639     }
2640   } else {
2641     grn_expr *e = (grn_expr *)expr;
2642     register grn_obj **s_ = ctx->impl->stack;
2643     register grn_obj *s0 = NULL;
2644     register grn_obj *s1 = NULL;
2645     register grn_obj **sp;
2646     register grn_obj *vp = e->values;
2647     grn_obj *res = NULL, *v0 = grn_expr_get_var_by_offset(ctx, expr, 0);
2648     grn_expr_code *code = e->codes, *ce = &e->codes[e->codes_curr];
2649     sp = s_ + stack_curr;
2650     while (code < ce) {
2651       switch (code->op) {
2652       case GRN_OP_NOP :
2653         code++;
2654         break;
2655       case GRN_OP_PUSH :
2656         PUSH1(code->value);
2657         code++;
2658         break;
2659       case GRN_OP_POP :
2660         {
2661           grn_obj *obj;
2662           POP1(obj);
2663           code++;
2664         }
2665         break;
2666       case GRN_OP_GET_REF :
2667         {
2668           grn_obj *col, *rec;
2669           if (code->nargs == 1) {
2670             rec = v0;
2671             if (code->value) {
2672               col = code->value;
2673               ALLOC1(res);
2674             } else {
2675               POP1ALLOC1(col, res);
2676             }
2677           } else {
2678             if (code->value) {
2679               col = code->value;
2680               POP1ALLOC1(rec, res);
2681             } else {
2682               POP2ALLOC1(rec, col, res);
2683             }
2684           }
2685           if (col->header.type == GRN_BULK) {
2686             grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec));
2687             col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col));
2688             if (col) { grn_expr_take_obj(ctx, (grn_obj *)e, col); }
2689           }
2690           if (col) {
2691             res->header.type = GRN_PTR;
2692             res->header.domain = GRN_ID_NIL;
2693             GRN_PTR_SET(ctx, res, col);
2694             GRN_UINT32_PUT(ctx, res, GRN_RECORD_VALUE(rec));
2695           } else {
2696             ERR(GRN_INVALID_ARGUMENT, "col resolve failed");
2697             goto exit;
2698           }
2699           code++;
2700         }
2701         break;
2702       case GRN_OP_CALL :
2703         {
2704           grn_obj *proc;
2705           if (code->value) {
2706             if (sp < s_ + code->nargs - 1) {
2707               ERR(GRN_INVALID_ARGUMENT, "stack error");
2708               goto exit;
2709             }
2710             proc = code->value;
2711             WITH_SPSAVE({
2712               grn_proc_call(ctx, proc, code->nargs - 1, expr);
2713             });
2714           } else {
2715             int offset = code->nargs;
2716             if (sp < s_ + offset) {
2717               ERR(GRN_INVALID_ARGUMENT, "stack error");
2718               goto exit;
2719             }
2720             proc = sp[-offset];
2721             if (grn_obj_is_window_function_proc(ctx, proc)) {
2722               grn_obj inspected;
2723               GRN_TEXT_INIT(&inspected, 0);
2724               grn_inspect(ctx, &inspected, proc);
2725               ERR(GRN_INVALID_ARGUMENT,
2726                   "window function can't be executed for each record: %.*s",
2727                   (int)GRN_TEXT_LEN(&inspected),
2728                   GRN_TEXT_VALUE(&inspected));
2729               GRN_OBJ_FIN(ctx, &inspected);
2730               goto exit;
2731             } else {
2732               WITH_SPSAVE({
2733                 grn_proc_call(ctx, proc, code->nargs - 1, expr);
2734               });
2735             }
2736             if (ctx->rc) {
2737               goto exit;
2738             }
2739             POP1(res);
2740             {
2741               grn_obj *proc_;
2742               POP1(proc_);
2743               if (proc != proc_) {
2744                 GRN_LOG(ctx, GRN_LOG_WARNING, "stack may be corrupt");
2745               }
2746             }
2747             PUSH1(res);
2748           }
2749         }
2750         code++;
2751         break;
2752       case GRN_OP_INTERN :
2753         {
2754           grn_obj *obj;
2755           POP1(obj);
2756           obj = GRN_OBJ_RESOLVE(ctx, obj);
2757           res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj));
2758           if (!res) { res = grn_ctx_get(ctx, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); }
2759           if (!res) {
2760             ERR(GRN_INVALID_ARGUMENT, "intern failed");
2761             goto exit;
2762           }
2763           PUSH1(res);
2764         }
2765         code++;
2766         break;
2767       case GRN_OP_TABLE_CREATE :
2768         {
2769           grn_obj *value_type, *key_type, *flags, *name;
2770           POP1(value_type);
2771           value_type = GRN_OBJ_RESOLVE(ctx, value_type);
2772           POP1(key_type);
2773           key_type = GRN_OBJ_RESOLVE(ctx, key_type);
2774           POP1(flags);
2775           flags = GRN_OBJ_RESOLVE(ctx, flags);
2776           POP1(name);
2777           name = GRN_OBJ_RESOLVE(ctx, name);
2778           res = grn_table_create(ctx, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name),
2779                                  NULL, GRN_UINT32_VALUE(flags),
2780                                  key_type, value_type);
2781           PUSH1(res);
2782         }
2783         code++;
2784         break;
2785       case GRN_OP_EXPR_GET_VAR :
2786         {
2787           grn_obj *name, *expr;
2788           POP1(name);
2789           name = GRN_OBJ_RESOLVE(ctx, name);
2790           POP1(expr);
2791           expr = GRN_OBJ_RESOLVE(ctx, expr);
2792           switch (name->header.domain) {
2793           case GRN_DB_INT32 :
2794             res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT32_VALUE(name));
2795             break;
2796           case GRN_DB_UINT32 :
2797             res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT32_VALUE(name));
2798             break;
2799           case GRN_DB_INT64 :
2800             res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT64_VALUE(name));
2801             break;
2802           case GRN_DB_UINT64 :
2803             res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT64_VALUE(name));
2804             break;
2805           case GRN_DB_SHORT_TEXT :
2806           case GRN_DB_TEXT :
2807           case GRN_DB_LONG_TEXT :
2808             res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name));
2809             break;
2810           default :
2811             ERR(GRN_INVALID_ARGUMENT, "invalid type");
2812             goto exit;
2813           }
2814           PUSH1(res);
2815         }
2816         code++;
2817         break;
2818       case GRN_OP_ASSIGN :
2819         {
2820           grn_obj *value, *var;
2821           if (code->value) {
2822             value = code->value;
2823           } else {
2824             POP1(value);
2825           }
2826           value = GRN_OBJ_RESOLVE(ctx, value);
2827           POP1(var);
2828           // var = GRN_OBJ_RESOLVE(ctx, var);
2829           if (var->header.type == GRN_PTR &&
2830               GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) {
2831             grn_obj *col = GRN_PTR_VALUE(var);
2832             grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *));
2833             grn_obj_set_value(ctx, col, rid, value, GRN_OBJ_SET);
2834           } else {
2835             VAR_SET_VALUE(ctx, var, value);
2836           }
2837           PUSH1(value);
2838         }
2839         code++;
2840         break;
2841       case GRN_OP_STAR_ASSIGN :
2842         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2843           INTEGER_ARITHMETIC_OPERATION_STAR,
2844           INTEGER_ARITHMETIC_OPERATION_STAR,
2845           INTEGER_ARITHMETIC_OPERATION_STAR,
2846           INTEGER_ARITHMETIC_OPERATION_STAR,
2847           FLOAT_ARITHMETIC_OPERATION_STAR,
2848           ARITHMETIC_OPERATION_NO_CHECK,
2849           ARITHMETIC_OPERATION_NO_CHECK,
2850           {
2851             ERR(GRN_INVALID_ARGUMENT, "variable *= \"string\" isn't supported");
2852             goto exit;
2853           });
2854         break;
2855       case GRN_OP_SLASH_ASSIGN :
2856         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2857           INTEGER_ARITHMETIC_OPERATION_SLASH,
2858           INTEGER_ARITHMETIC_OPERATION_SLASH,
2859           INTEGER_ARITHMETIC_OPERATION_SLASH,
2860           INTEGER_ARITHMETIC_OPERATION_SLASH,
2861           FLOAT_ARITHMETIC_OPERATION_SLASH,
2862           ARITHMETIC_OPERATION_NO_CHECK,
2863           ARITHMETIC_OPERATION_NO_CHECK,
2864           {
2865             ERR(GRN_INVALID_ARGUMENT, "variable /= \"string\" isn't supported");
2866             goto exit;
2867           });
2868         break;
2869       case GRN_OP_MOD_ASSIGN :
2870         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2871           INTEGER_ARITHMETIC_OPERATION_MOD,
2872           INTEGER_ARITHMETIC_OPERATION_MOD,
2873           INTEGER_ARITHMETIC_OPERATION_MOD,
2874           INTEGER_ARITHMETIC_OPERATION_MOD,
2875           FLOAT_ARITHMETIC_OPERATION_MOD,
2876           ARITHMETIC_OPERATION_NO_CHECK,
2877           ARITHMETIC_OPERATION_NO_CHECK,
2878           {
2879             ERR(GRN_INVALID_ARGUMENT, "variable %%= \"string\" isn't supported");
2880             goto exit;
2881           });
2882         break;
2883       case GRN_OP_PLUS_ASSIGN :
2884         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2885           INTEGER_ARITHMETIC_OPERATION_PLUS,
2886           INTEGER_ARITHMETIC_OPERATION_PLUS,
2887           INTEGER_ARITHMETIC_OPERATION_PLUS,
2888           INTEGER_ARITHMETIC_OPERATION_PLUS,
2889           FLOAT_ARITHMETIC_OPERATION_PLUS,
2890           ARITHMETIC_OPERATION_NO_CHECK,
2891           ARITHMETIC_OPERATION_NO_CHECK,
2892           {
2893             ERR(GRN_INVALID_ARGUMENT, "variable += \"string\" isn't supported");
2894             goto exit;
2895           });
2896         break;
2897       case GRN_OP_MINUS_ASSIGN :
2898         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2899           INTEGER_ARITHMETIC_OPERATION_MINUS,
2900           INTEGER_ARITHMETIC_OPERATION_MINUS,
2901           INTEGER_ARITHMETIC_OPERATION_MINUS,
2902           INTEGER_ARITHMETIC_OPERATION_MINUS,
2903           FLOAT_ARITHMETIC_OPERATION_MINUS,
2904           ARITHMETIC_OPERATION_NO_CHECK,
2905           ARITHMETIC_OPERATION_NO_CHECK,
2906           {
2907             ERR(GRN_INVALID_ARGUMENT, "variable -= \"string\" isn't supported");
2908             goto exit;
2909           });
2910         break;
2911       case GRN_OP_SHIFTL_ASSIGN :
2912         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2913           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
2914           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
2915           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
2916           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
2917           FLOAT_ARITHMETIC_OPERATION_SHIFTL,
2918           ARITHMETIC_OPERATION_NO_CHECK,
2919           ARITHMETIC_OPERATION_NO_CHECK,
2920           {
2921             ERR(GRN_INVALID_ARGUMENT, "variable <<= \"string\" isn't supported");
2922             goto exit;
2923           });
2924         break;
2925       case GRN_OP_SHIFTR_ASSIGN :
2926         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2927           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
2928           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
2929           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
2930           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
2931           FLOAT_ARITHMETIC_OPERATION_SHIFTR,
2932           ARITHMETIC_OPERATION_NO_CHECK,
2933           ARITHMETIC_OPERATION_NO_CHECK,
2934           {
2935             ERR(GRN_INVALID_ARGUMENT, "variable >>= \"string\" isn't supported");
2936             goto exit;
2937           });
2938         break;
2939       case GRN_OP_SHIFTRR_ASSIGN :
2940         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2941           INTEGER8_ARITHMETIC_OPERATION_SHIFTRR,
2942           INTEGER16_ARITHMETIC_OPERATION_SHIFTRR,
2943           INTEGER32_ARITHMETIC_OPERATION_SHIFTRR,
2944           INTEGER64_ARITHMETIC_OPERATION_SHIFTRR,
2945           FLOAT_ARITHMETIC_OPERATION_SHIFTRR,
2946           ARITHMETIC_OPERATION_NO_CHECK,
2947           ARITHMETIC_OPERATION_NO_CHECK,
2948           {
2949             ERR(GRN_INVALID_ARGUMENT,
2950                 "variable >>>= \"string\" isn't supported");
2951             goto exit;
2952           });
2953         break;
2954       case GRN_OP_AND_ASSIGN :
2955         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2956           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
2957           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
2958           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
2959           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
2960           FLOAT_ARITHMETIC_OPERATION_BITWISE_AND,
2961           ARITHMETIC_OPERATION_NO_CHECK,
2962           ARITHMETIC_OPERATION_NO_CHECK,
2963           {
2964             ERR(GRN_INVALID_ARGUMENT, "variable &= \"string\" isn't supported");
2965             goto exit;
2966           });
2967         break;
2968       case GRN_OP_OR_ASSIGN :
2969         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2970           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
2971           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
2972           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
2973           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
2974           FLOAT_ARITHMETIC_OPERATION_BITWISE_OR,
2975           ARITHMETIC_OPERATION_NO_CHECK,
2976           ARITHMETIC_OPERATION_NO_CHECK,
2977           {
2978             ERR(GRN_INVALID_ARGUMENT, "variable |= \"string\" isn't supported");
2979             goto exit;
2980           });
2981         break;
2982       case GRN_OP_XOR_ASSIGN :
2983         ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
2984           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
2985           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
2986           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
2987           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
2988           FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR,
2989           ARITHMETIC_OPERATION_NO_CHECK,
2990           ARITHMETIC_OPERATION_NO_CHECK,
2991           {
2992             ERR(GRN_INVALID_ARGUMENT, "variable ^= \"string\" isn't supported");
2993             goto exit;
2994           });
2995         break;
2996       case GRN_OP_JUMP :
2997         code += code->nargs + 1;
2998         break;
2999       case GRN_OP_CJUMP :
3000         {
3001           grn_obj *v;
3002           POP1(v);
3003           if (!grn_obj_is_true(ctx, v)) {
3004             code += code->nargs;
3005           }
3006         }
3007         code++;
3008         break;
3009       case GRN_OP_GET_VALUE :
3010         {
3011           grn_obj *col, *rec;
3012           do {
3013             if (code->nargs == 1) {
3014               rec = v0;
3015               if (code->value) {
3016                 col = code->value;
3017                 ALLOC1(res);
3018               } else {
3019                 POP1ALLOC1(col, res);
3020               }
3021             } else {
3022               if (code->value) {
3023                 col = code->value;
3024                 POP1ALLOC1(rec, res);
3025               } else {
3026                 POP2ALLOC1(rec, col, res);
3027               }
3028             }
3029             if (col->header.type == GRN_BULK) {
3030               grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec));
3031               col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col));
3032               if (col) { grn_expr_take_obj(ctx, (grn_obj *)expr, col); }
3033             }
3034             if (!col) {
3035               ERR(GRN_INVALID_ARGUMENT, "col resolve failed");
3036               goto exit;
3037             }
3038             grn_obj_reinit_for(ctx, res, col);
3039             grn_obj_get_value(ctx, col, GRN_RECORD_VALUE(rec), res);
3040             code++;
3041           } while (code < ce && code->op == GRN_OP_GET_VALUE);
3042         }
3043         break;
3044       case GRN_OP_OBJ_SEARCH :
3045         {
3046           grn_obj *op, *query, *index;
3047           // todo : grn_search_optarg optarg;
3048           POP1(op);
3049           op = GRN_OBJ_RESOLVE(ctx, op);
3050           POP1(res);
3051           res = GRN_OBJ_RESOLVE(ctx, res);
3052           POP1(query);
3053           query = GRN_OBJ_RESOLVE(ctx, query);
3054           POP1(index);
3055           index = GRN_OBJ_RESOLVE(ctx, index);
3056           grn_obj_search(ctx, index, query, res,
3057                          (grn_operator)GRN_UINT32_VALUE(op), NULL);
3058         }
3059         code++;
3060         break;
3061       case GRN_OP_TABLE_SELECT :
3062         {
3063           grn_obj *op, *res, *expr, *table;
3064           POP1(op);
3065           op = GRN_OBJ_RESOLVE(ctx, op);
3066           POP1(res);
3067           res = GRN_OBJ_RESOLVE(ctx, res);
3068           POP1(expr);
3069           expr = GRN_OBJ_RESOLVE(ctx, expr);
3070           POP1(table);
3071           table = GRN_OBJ_RESOLVE(ctx, table);
3072           WITH_SPSAVE({
3073             grn_table_select(ctx, table, expr, res, (grn_operator)GRN_UINT32_VALUE(op));
3074           });
3075           PUSH1(res);
3076         }
3077         code++;
3078         break;
3079       case GRN_OP_TABLE_SORT :
3080         {
3081           grn_obj *keys_, *res, *limit, *table;
3082           POP1(keys_);
3083           keys_ = GRN_OBJ_RESOLVE(ctx, keys_);
3084           POP1(res);
3085           res = GRN_OBJ_RESOLVE(ctx, res);
3086           POP1(limit);
3087           limit = GRN_OBJ_RESOLVE(ctx, limit);
3088           POP1(table);
3089           table = GRN_OBJ_RESOLVE(ctx, table);
3090           {
3091             grn_table_sort_key *keys;
3092             const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256];
3093             int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL);
3094             if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
3095               int i, n_keys = 0;
3096               for (i = 0; i < n; i++) {
3097                 uint32_t len = (uint32_t) (tokbuf[i] - p);
3098                 grn_obj *col = grn_obj_column(ctx, table, p, len);
3099                 if (col) {
3100                   keys[n_keys].key = col;
3101                   keys[n_keys].flags = GRN_TABLE_SORT_ASC;
3102                   keys[n_keys].offset = 0;
3103                   n_keys++;
3104                 } else {
3105                   if (p[0] == ':' && p[1] == 'd' && len == 2 && n_keys) {
3106                     keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC;
3107                   }
3108                 }
3109                 p = tokbuf[i] + 1;
3110               }
3111               WITH_SPSAVE({
3112                 grn_table_sort(ctx, table, 0, GRN_INT32_VALUE(limit), res, keys, n_keys);
3113               });
3114               for (i = 0; i < n_keys; i++) {
3115                 grn_obj_unlink(ctx, keys[i].key);
3116               }
3117               GRN_FREE(keys);
3118             }
3119           }
3120         }
3121         code++;
3122         break;
3123       case GRN_OP_TABLE_GROUP :
3124         {
3125           grn_obj *res, *keys_, *table;
3126           POP1(res);
3127           res = GRN_OBJ_RESOLVE(ctx, res);
3128           POP1(keys_);
3129           keys_ = GRN_OBJ_RESOLVE(ctx, keys_);
3130           POP1(table);
3131           table = GRN_OBJ_RESOLVE(ctx, table);
3132           {
3133             grn_table_sort_key *keys;
3134             grn_table_group_result results;
3135             const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256];
3136             int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL);
3137             if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
3138               int i, n_keys = 0;
3139               for (i = 0; i < n; i++) {
3140                 uint32_t len = (uint32_t) (tokbuf[i] - p);
3141                 grn_obj *col = grn_obj_column(ctx, table, p, len);
3142                 if (col) {
3143                   keys[n_keys].key = col;
3144                   keys[n_keys].flags = GRN_TABLE_SORT_ASC;
3145                   keys[n_keys].offset = 0;
3146                   n_keys++;
3147                 } else if (n_keys) {
3148                   if (p[0] == ':' && p[1] == 'd' && len == 2) {
3149                     keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC;
3150                   } else {
3151                     keys[n_keys - 1].offset = grn_atoi(p, p + len, NULL);
3152                   }
3153                 }
3154                 p = tokbuf[i] + 1;
3155               }
3156               /* todo : support multi-results */
3157               results.table = res;
3158               results.key_begin = 0;
3159               results.key_end = 0;
3160               results.limit = 0;
3161               results.flags = 0;
3162               results.op = GRN_OP_OR;
3163               WITH_SPSAVE({
3164                 grn_table_group(ctx, table, keys, n_keys, &results, 1);
3165               });
3166               for (i = 0; i < n_keys; i++) {
3167                 grn_obj_unlink(ctx, keys[i].key);
3168               }
3169               GRN_FREE(keys);
3170             }
3171           }
3172         }
3173         code++;
3174         break;
3175       case GRN_OP_JSON_PUT :
3176         {
3177           grn_obj_format format;
3178           grn_obj *str, *table, *res;
3179           POP1(res);
3180           res = GRN_OBJ_RESOLVE(ctx, res);
3181           POP1(str);
3182           str = GRN_OBJ_RESOLVE(ctx, str);
3183           POP1(table);
3184           table = GRN_OBJ_RESOLVE(ctx, table);
3185           GRN_OBJ_FORMAT_INIT(&format, grn_table_size(ctx, table), 0, -1, 0);
3186           format.flags = 0;
3187           grn_obj_columns(ctx, table,
3188                           GRN_TEXT_VALUE(str), GRN_TEXT_LEN(str), &format.columns);
3189           grn_text_otoj(ctx, res, table, &format);
3190           GRN_OBJ_FORMAT_FIN(ctx, &format);
3191         }
3192         code++;
3193         break;
3194       case GRN_OP_AND :
3195         {
3196           grn_obj *x, *y;
3197           grn_obj *result = NULL;
3198           POP2ALLOC1(x, y, res);
3199           if (grn_obj_is_true(ctx, x)) {
3200             if (grn_obj_is_true(ctx, y)) {
3201               result = y;
3202             }
3203           }
3204           if (result) {
3205             if (res != result) {
3206               grn_obj_reinit(ctx, res, result->header.domain, 0);
3207               grn_obj_cast(ctx, result, res, GRN_FALSE);
3208             }
3209           } else {
3210             grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3211             GRN_BOOL_SET(ctx, res, GRN_FALSE);
3212           }
3213         }
3214         code++;
3215         break;
3216       case GRN_OP_OR :
3217         {
3218           grn_obj *x, *y;
3219           grn_obj *result;
3220           POP2ALLOC1(x, y, res);
3221           if (grn_obj_is_true(ctx, x)) {
3222             result = x;
3223           } else {
3224             if (grn_obj_is_true(ctx, y)) {
3225               result = y;
3226             } else {
3227               result = NULL;
3228             }
3229           }
3230           if (result) {
3231             if (res != result) {
3232               grn_obj_reinit(ctx, res, result->header.domain, 0);
3233               grn_obj_cast(ctx, result, res, GRN_FALSE);
3234             }
3235           } else {
3236             grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3237             GRN_BOOL_SET(ctx, res, GRN_FALSE);
3238           }
3239         }
3240         code++;
3241         break;
3242       case GRN_OP_AND_NOT :
3243         {
3244           grn_obj *x, *y;
3245           grn_bool is_true;
3246           POP2ALLOC1(x, y, res);
3247           if (!grn_obj_is_true(ctx, x) || grn_obj_is_true(ctx, y)) {
3248             is_true = GRN_FALSE;
3249           } else {
3250             is_true = GRN_TRUE;
3251           }
3252           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3253           GRN_BOOL_SET(ctx, res, is_true);
3254         }
3255         code++;
3256         break;
3257       case GRN_OP_ADJUST :
3258         {
3259           /* todo */
3260         }
3261         code++;
3262         break;
3263       case GRN_OP_MATCH :
3264         {
3265           grn_obj *x, *y;
3266           grn_bool matched;
3267           POP1(y);
3268           POP1(x);
3269           WITH_SPSAVE({
3270             matched = grn_operator_exec_match(ctx, x, y);
3271           });
3272           ALLOC1(res);
3273           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3274           GRN_BOOL_SET(ctx, res, matched);
3275         }
3276         code++;
3277         break;
3278       case GRN_OP_EQUAL :
3279         {
3280           grn_bool is_equal;
3281           grn_obj *x, *y;
3282           POP2ALLOC1(x, y, res);
3283           is_equal = grn_operator_exec_equal(ctx, x, y);
3284           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3285           GRN_BOOL_SET(ctx, res, is_equal);
3286         }
3287         code++;
3288         break;
3289       case GRN_OP_NOT_EQUAL :
3290         {
3291           grn_bool is_not_equal;
3292           grn_obj *x, *y;
3293           POP2ALLOC1(x, y, res);
3294           is_not_equal = grn_operator_exec_not_equal(ctx, x, y);
3295           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3296           GRN_BOOL_SET(ctx, res, is_not_equal);
3297         }
3298         code++;
3299         break;
3300       case GRN_OP_PREFIX :
3301         {
3302           grn_obj *x, *y;
3303           grn_bool matched;
3304           POP1(y);
3305           POP1(x);
3306           WITH_SPSAVE({
3307             matched = grn_operator_exec_prefix(ctx, x, y);
3308           });
3309           ALLOC1(res);
3310           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3311           GRN_BOOL_SET(ctx, res, matched);
3312         }
3313         code++;
3314         break;
3315       case GRN_OP_SUFFIX :
3316         {
3317           grn_obj *x, *y;
3318           grn_bool matched = GRN_FALSE;
3319           POP2ALLOC1(x, y, res);
3320           if (GRN_TEXT_LEN(x) >= GRN_TEXT_LEN(y) &&
3321               !memcmp(GRN_TEXT_VALUE(x) + GRN_TEXT_LEN(x) - GRN_TEXT_LEN(y),
3322                       GRN_TEXT_VALUE(y), GRN_TEXT_LEN(y))) {
3323             matched = GRN_TRUE;
3324           }
3325           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3326           GRN_BOOL_SET(ctx, res, matched);
3327         }
3328         code++;
3329         break;
3330       case GRN_OP_LESS :
3331         {
3332           grn_bool r;
3333           grn_obj *x, *y;
3334           POP2ALLOC1(x, y, res);
3335           r = grn_operator_exec_less(ctx, x, y);
3336           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3337           GRN_BOOL_SET(ctx, res, r);
3338         }
3339         code++;
3340         break;
3341       case GRN_OP_GREATER :
3342         {
3343           grn_bool r;
3344           grn_obj *x, *y;
3345           POP2ALLOC1(x, y, res);
3346           r = grn_operator_exec_greater(ctx, x, y);
3347           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3348           GRN_BOOL_SET(ctx, res, r);
3349         }
3350         code++;
3351         break;
3352       case GRN_OP_LESS_EQUAL :
3353         {
3354           grn_bool r;
3355           grn_obj *x, *y;
3356           POP2ALLOC1(x, y, res);
3357           r = grn_operator_exec_less_equal(ctx, x, y);
3358           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3359           GRN_BOOL_SET(ctx, res, r);
3360         }
3361         code++;
3362         break;
3363       case GRN_OP_GREATER_EQUAL :
3364         {
3365           grn_bool r;
3366           grn_obj *x, *y;
3367           POP2ALLOC1(x, y, res);
3368           r = grn_operator_exec_greater_equal(ctx, x, y);
3369           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3370           GRN_BOOL_SET(ctx, res, r);
3371         }
3372         code++;
3373         break;
3374       case GRN_OP_GEO_DISTANCE1 :
3375         {
3376           grn_obj *value;
3377           double lng1, lat1, lng2, lat2, x, y, d;
3378           POP1(value);
3379           lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3380           POP1(value);
3381           lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3382           POP1(value);
3383           lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3384           POP1ALLOC1(value, res);
3385           lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3386           x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
3387           y = (lat2 - lat1);
3388           d = sqrt((x * x) + (y * y)) * GEO_RADIOUS;
3389           res->header.type = GRN_BULK;
3390           res->header.domain = GRN_DB_FLOAT;
3391           GRN_FLOAT_SET(ctx, res, d);
3392         }
3393         code++;
3394         break;
3395       case GRN_OP_GEO_DISTANCE2 :
3396         {
3397           grn_obj *value;
3398           double lng1, lat1, lng2, lat2, x, y, d;
3399           POP1(value);
3400           lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3401           POP1(value);
3402           lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3403           POP1(value);
3404           lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3405           POP1ALLOC1(value, res);
3406           lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3407           x = sin(fabs(lng2 - lng1) * 0.5);
3408           y = sin(fabs(lat2 - lat1) * 0.5);
3409           d = asin(sqrt((y * y) + cos(lat1) * cos(lat2) * x * x)) * 2 * GEO_RADIOUS;
3410           res->header.type = GRN_BULK;
3411           res->header.domain = GRN_DB_FLOAT;
3412           GRN_FLOAT_SET(ctx, res, d);
3413         }
3414         code++;
3415         break;
3416       case GRN_OP_GEO_DISTANCE3 :
3417         {
3418           grn_obj *value;
3419           double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d;
3420           POP1(value);
3421           lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3422           POP1(value);
3423           lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3424           POP1(value);
3425           lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3426           POP1ALLOC1(value, res);
3427           lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3428           p = (lat1 + lat2) * 0.5;
3429           q = (1 - GEO_BES_C3 * sin(p) * sin(p));
3430           m = GEO_BES_C1 / sqrt(q * q * q);
3431           n = GEO_BES_C2 / sqrt(q);
3432           x = n * cos(p) * fabs(lng1 - lng2);
3433           y = m * fabs(lat1 - lat2);
3434           d = sqrt((x * x) + (y * y));
3435           res->header.type = GRN_BULK;
3436           res->header.domain = GRN_DB_FLOAT;
3437           GRN_FLOAT_SET(ctx, res, d);
3438         }
3439         code++;
3440         break;
3441       case GRN_OP_GEO_DISTANCE4 :
3442         {
3443           grn_obj *value;
3444           double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d;
3445           POP1(value);
3446           lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3447           POP1(value);
3448           lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3449           POP1(value);
3450           lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3451           POP1ALLOC1(value, res);
3452           lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3453           p = (lat1 + lat2) * 0.5;
3454           q = (1 - GEO_GRS_C3 * sin(p) * sin(p));
3455           m = GEO_GRS_C1 / sqrt(q * q * q);
3456           n = GEO_GRS_C2 / sqrt(q);
3457           x = n * cos(p) * fabs(lng1 - lng2);
3458           y = m * fabs(lat1 - lat2);
3459           d = sqrt((x * x) + (y * y));
3460           res->header.type = GRN_BULK;
3461           res->header.domain = GRN_DB_FLOAT;
3462           GRN_FLOAT_SET(ctx, res, d);
3463         }
3464         code++;
3465         break;
3466       case GRN_OP_GEO_WITHINP5 :
3467         {
3468           int r;
3469           grn_obj *value;
3470           double lng0, lat0, lng1, lat1, x, y, d;
3471           POP1(value);
3472           lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3473           POP1(value);
3474           lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3475           POP1(value);
3476           lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3477           POP1(value);
3478           lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3479           POP1ALLOC1(value, res);
3480           x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5);
3481           y = (lat1 - lat0);
3482           d = sqrt((x * x) + (y * y)) * GEO_RADIOUS;
3483           switch (value->header.domain) {
3484           case GRN_DB_INT32 :
3485             r = d <= GRN_INT32_VALUE(value);
3486             break;
3487           case GRN_DB_FLOAT :
3488             r = d <= GRN_FLOAT_VALUE(value);
3489             break;
3490           default :
3491             r = 0;
3492             break;
3493           }
3494           GRN_INT32_SET(ctx, res, r);
3495           res->header.type = GRN_BULK;
3496           res->header.domain = GRN_DB_INT32;
3497         }
3498         code++;
3499         break;
3500       case GRN_OP_GEO_WITHINP6 :
3501         {
3502           int r;
3503           grn_obj *value;
3504           double lng0, lat0, lng1, lat1, lng2, lat2, x, y, d;
3505           POP1(value);
3506           lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3507           POP1(value);
3508           lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3509           POP1(value);
3510           lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3511           POP1(value);
3512           lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3513           POP1(value);
3514           lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3515           POP1ALLOC1(value, res);
3516           lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
3517           x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5);
3518           y = (lat1 - lat0);
3519           d = (x * x) + (y * y);
3520           x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
3521           y = (lat2 - lat1);
3522           r = d <= (x * x) + (y * y);
3523           GRN_INT32_SET(ctx, res, r);
3524           res->header.type = GRN_BULK;
3525           res->header.domain = GRN_DB_INT32;
3526         }
3527         code++;
3528         break;
3529       case GRN_OP_GEO_WITHINP8 :
3530         {
3531           int r;
3532           grn_obj *value;
3533           int64_t ln0, la0, ln1, la1, ln2, la2, ln3, la3;
3534           POP1(value);
3535           ln0 = GRN_INT32_VALUE(value);
3536           POP1(value);
3537           la0 = GRN_INT32_VALUE(value);
3538           POP1(value);
3539           ln1 = GRN_INT32_VALUE(value);
3540           POP1(value);
3541           la1 = GRN_INT32_VALUE(value);
3542           POP1(value);
3543           ln2 = GRN_INT32_VALUE(value);
3544           POP1(value);
3545           la2 = GRN_INT32_VALUE(value);
3546           POP1(value);
3547           ln3 = GRN_INT32_VALUE(value);
3548           POP1ALLOC1(value, res);
3549           la3 = GRN_INT32_VALUE(value);
3550           r = ((ln2 <= ln0) && (ln0 <= ln3) && (la2 <= la0) && (la0 <= la3));
3551           GRN_INT32_SET(ctx, res, r);
3552           res->header.type = GRN_BULK;
3553           res->header.domain = GRN_DB_INT32;
3554         }
3555         code++;
3556         break;
3557       case GRN_OP_PLUS :
3558         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3559           "+",
3560           INTEGER_ARITHMETIC_OPERATION_PLUS,
3561           INTEGER_ARITHMETIC_OPERATION_PLUS,
3562           INTEGER_ARITHMETIC_OPERATION_PLUS,
3563           INTEGER_ARITHMETIC_OPERATION_PLUS,
3564           FLOAT_ARITHMETIC_OPERATION_PLUS,
3565           ARITHMETIC_OPERATION_NO_CHECK,
3566           ARITHMETIC_OPERATION_NO_CHECK,
3567           {
3568             if (x == res) {
3569               grn_obj_cast(ctx, y, res, GRN_FALSE);
3570             } else if (y == res) {
3571               grn_obj buffer;
3572               GRN_TEXT_INIT(&buffer, 0);
3573               grn_obj_cast(ctx, x, &buffer, GRN_FALSE);
3574               grn_obj_cast(ctx, y, &buffer, GRN_FALSE);
3575               GRN_BULK_REWIND(res);
3576               grn_obj_cast(ctx, &buffer, res, GRN_FALSE);
3577               GRN_OBJ_FIN(ctx, &buffer);
3578             } else {
3579               GRN_BULK_REWIND(res);
3580               grn_obj_cast(ctx, x, res, GRN_FALSE);
3581               grn_obj_cast(ctx, y, res, GRN_FALSE);
3582             }
3583           }
3584           ,);
3585         break;
3586       case GRN_OP_MINUS :
3587         if (code->nargs == 1) {
3588           ARITHMETIC_UNARY_OPERATION_DISPATCH(
3589             INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS,
3590             FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS,
3591             ARITHMETIC_OPERATION_NO_CHECK,
3592             ARITHMETIC_OPERATION_NO_CHECK,
3593             {
3594               long long int x_;
3595 
3596               res->header.type = GRN_BULK;
3597               res->header.domain = GRN_DB_INT64;
3598 
3599               GRN_INT64_SET(ctx, res, 0);
3600               grn_obj_cast(ctx, x, res, GRN_FALSE);
3601               x_ = GRN_INT64_VALUE(res);
3602 
3603               GRN_INT64_SET(ctx, res, -x_);
3604             }
3605             ,);
3606         } else {
3607           ARITHMETIC_BINARY_OPERATION_DISPATCH(
3608             "-",
3609             INTEGER_ARITHMETIC_OPERATION_MINUS,
3610             INTEGER_ARITHMETIC_OPERATION_MINUS,
3611             INTEGER_ARITHMETIC_OPERATION_MINUS,
3612             INTEGER_ARITHMETIC_OPERATION_MINUS,
3613             FLOAT_ARITHMETIC_OPERATION_MINUS,
3614             ARITHMETIC_OPERATION_NO_CHECK,
3615             ARITHMETIC_OPERATION_NO_CHECK,
3616             {
3617               ERR(GRN_INVALID_ARGUMENT,
3618                   "\"string\" - \"string\" "
3619                   "isn't supported");
3620               goto exit;
3621             }
3622             ,);
3623         }
3624         break;
3625       case GRN_OP_STAR :
3626         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3627           "*",
3628           INTEGER_ARITHMETIC_OPERATION_STAR,
3629           INTEGER_ARITHMETIC_OPERATION_STAR,
3630           INTEGER_ARITHMETIC_OPERATION_STAR,
3631           INTEGER_ARITHMETIC_OPERATION_STAR,
3632           FLOAT_ARITHMETIC_OPERATION_STAR,
3633           ARITHMETIC_OPERATION_NO_CHECK,
3634           ARITHMETIC_OPERATION_NO_CHECK,
3635           {
3636             ERR(GRN_INVALID_ARGUMENT,
3637                 "\"string\" * \"string\" "
3638                 "isn't supported");
3639             goto exit;
3640           }
3641           ,);
3642         break;
3643       case GRN_OP_SLASH :
3644         DIVISION_OPERATION_DISPATCH(
3645           SIGNED_INTEGER_DIVISION_OPERATION_SLASH,
3646           UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH,
3647           FLOAT_DIVISION_OPERATION_SLASH,
3648           {
3649             ERR(GRN_INVALID_ARGUMENT,
3650                 "\"string\" / \"string\" "
3651                 "isn't supported");
3652             goto exit;
3653           });
3654         break;
3655       case GRN_OP_MOD :
3656         DIVISION_OPERATION_DISPATCH(
3657           SIGNED_INTEGER_DIVISION_OPERATION_MOD,
3658           UNSIGNED_INTEGER_DIVISION_OPERATION_MOD,
3659           FLOAT_DIVISION_OPERATION_MOD,
3660           {
3661             ERR(GRN_INVALID_ARGUMENT,
3662                 "\"string\" %% \"string\" "
3663                 "isn't supported");
3664             goto exit;
3665           });
3666         break;
3667       case GRN_OP_BITWISE_NOT :
3668         ARITHMETIC_UNARY_OPERATION_DISPATCH(
3669           INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT,
3670           FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT,
3671           ARITHMETIC_OPERATION_NO_CHECK,
3672           ARITHMETIC_OPERATION_NO_CHECK,
3673           TEXT_UNARY_ARITHMETIC_OPERATION(~),);
3674         break;
3675       case GRN_OP_BITWISE_OR :
3676         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3677           "|",
3678           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
3679           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
3680           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
3681           INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
3682           FLOAT_ARITHMETIC_OPERATION_BITWISE_OR,
3683           ARITHMETIC_OPERATION_NO_CHECK,
3684           ARITHMETIC_OPERATION_NO_CHECK,
3685           TEXT_ARITHMETIC_OPERATION(|),);
3686         break;
3687       case GRN_OP_BITWISE_XOR :
3688         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3689           "^",
3690           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
3691           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
3692           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
3693           INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
3694           FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR,
3695           ARITHMETIC_OPERATION_NO_CHECK,
3696           ARITHMETIC_OPERATION_NO_CHECK,
3697           TEXT_ARITHMETIC_OPERATION(^),);
3698         break;
3699       case GRN_OP_BITWISE_AND :
3700         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3701           "&",
3702           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
3703           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
3704           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
3705           INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
3706           FLOAT_ARITHMETIC_OPERATION_BITWISE_AND,
3707           ARITHMETIC_OPERATION_NO_CHECK,
3708           ARITHMETIC_OPERATION_NO_CHECK,
3709           TEXT_ARITHMETIC_OPERATION(&),);
3710         break;
3711       case GRN_OP_SHIFTL :
3712         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3713           "<<",
3714           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
3715           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
3716           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
3717           INTEGER_ARITHMETIC_OPERATION_SHIFTL,
3718           FLOAT_ARITHMETIC_OPERATION_SHIFTL,
3719           ARITHMETIC_OPERATION_NO_CHECK,
3720           ARITHMETIC_OPERATION_NO_CHECK,
3721           TEXT_ARITHMETIC_OPERATION(<<),);
3722         break;
3723       case GRN_OP_SHIFTR :
3724         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3725           ">>",
3726           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
3727           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
3728           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
3729           INTEGER_ARITHMETIC_OPERATION_SHIFTR,
3730           FLOAT_ARITHMETIC_OPERATION_SHIFTR,
3731           ARITHMETIC_OPERATION_NO_CHECK,
3732           ARITHMETIC_OPERATION_NO_CHECK,
3733           TEXT_ARITHMETIC_OPERATION(>>),);
3734         break;
3735       case GRN_OP_SHIFTRR :
3736         ARITHMETIC_BINARY_OPERATION_DISPATCH(
3737           ">>>",
3738           INTEGER8_ARITHMETIC_OPERATION_SHIFTRR,
3739           INTEGER16_ARITHMETIC_OPERATION_SHIFTRR,
3740           INTEGER32_ARITHMETIC_OPERATION_SHIFTRR,
3741           INTEGER64_ARITHMETIC_OPERATION_SHIFTRR,
3742           FLOAT_ARITHMETIC_OPERATION_SHIFTRR,
3743           ARITHMETIC_OPERATION_NO_CHECK,
3744           ARITHMETIC_OPERATION_NO_CHECK,
3745           {
3746             long long unsigned int x_;
3747             long long unsigned int y_;
3748 
3749             res->header.type = GRN_BULK;
3750             res->header.domain = GRN_DB_INT64;
3751 
3752             GRN_INT64_SET(ctx, res, 0);
3753             grn_obj_cast(ctx, x, res, GRN_FALSE);
3754             x_ = GRN_INT64_VALUE(res);
3755 
3756             GRN_INT64_SET(ctx, res, 0);
3757             grn_obj_cast(ctx, y, res, GRN_FALSE);
3758             y_ = GRN_INT64_VALUE(res);
3759 
3760             GRN_INT64_SET(ctx, res, x_ >> y_);
3761           }
3762           ,);
3763         break;
3764       case GRN_OP_INCR :
3765         UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_INCR);
3766         break;
3767       case GRN_OP_DECR :
3768         UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_DECR);
3769         break;
3770       case GRN_OP_INCR_POST :
3771         UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_INCR);
3772         break;
3773       case GRN_OP_DECR_POST :
3774         UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_DECR);
3775         break;
3776       case GRN_OP_NOT :
3777         {
3778           grn_obj *value;
3779           grn_bool value_boolean;
3780           POP1ALLOC1(value, res);
3781           GRN_OBJ_IS_TRUE(ctx, value, value_boolean);
3782           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3783           GRN_BOOL_SET(ctx, res, !value_boolean);
3784         }
3785         code++;
3786         break;
3787       case GRN_OP_GET_MEMBER :
3788         {
3789           grn_obj *receiver, *index_or_key;
3790           POP2ALLOC1(receiver, index_or_key, res);
3791           if (receiver->header.type == GRN_PTR) {
3792             grn_obj *index = index_or_key;
3793             grn_expr_exec_get_member_vector(ctx, expr, receiver, index, res);
3794           } else {
3795             grn_obj *key = index_or_key;
3796             grn_expr_exec_get_member_table(ctx, expr, receiver, key, res);
3797           }
3798           code++;
3799         }
3800         break;
3801       case GRN_OP_REGEXP :
3802         {
3803           grn_obj *target, *pattern;
3804           grn_bool matched;
3805           POP1(pattern);
3806           POP1(target);
3807           WITH_SPSAVE({
3808             matched = grn_operator_exec_regexp(ctx, target, pattern);
3809           });
3810           ALLOC1(res);
3811           grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
3812           GRN_BOOL_SET(ctx, res, matched);
3813         }
3814         code++;
3815         break;
3816       default :
3817         ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "not implemented operator assigned");
3818         goto exit;
3819         break;
3820       }
3821     }
3822     ctx->impl->stack_curr = sp - s_;
3823   }
3824   if (ctx->impl->stack_curr + nargs > stack_curr) {
3825     val = grn_ctx_pop(ctx);
3826   }
3827 exit :
3828   if (ctx->impl->stack_curr + nargs > stack_curr) {
3829     /*
3830       GRN_LOG(ctx, GRN_LOG_WARNING, "nargs=%d stack balance=%d",
3831       nargs, stack_curr - ctx->impl->stack_curr);
3832     */
3833     ctx->impl->stack_curr = stack_curr - nargs;
3834   }
3835   GRN_API_RETURN(val);
3836 }
3837 
3838 grn_obj *
grn_expr_get_value(grn_ctx * ctx,grn_obj * expr,int offset)3839 grn_expr_get_value(grn_ctx *ctx, grn_obj *expr, int offset)
3840 {
3841   grn_obj *res = NULL;
3842   grn_expr *e = (grn_expr *)expr;
3843   GRN_API_ENTER;
3844   if (0 <= offset && offset < e->values_size) {
3845     res = &e->values[offset];
3846   }
3847   GRN_API_RETURN(res);
3848 }
3849 
3850 #define DEFAULT_WEIGHT 5
3851 #define DEFAULT_DECAYSTEP 2
3852 #define DEFAULT_MAX_INTERVAL 10
3853 #define DEFAULT_SIMILARITY_THRESHOLD 0
3854 #define DEFAULT_TERM_EXTRACT_POLICY 0
3855 #define DEFAULT_WEIGHT_VECTOR_SIZE 4096
3856 
3857 #define GRN_SCAN_INFO_MAX_N_ARGS 128
3858 
3859 struct _grn_scan_info {
3860   uint32_t start;
3861   uint32_t end;
3862   int32_t nargs;
3863   int flags;
3864   grn_operator op;
3865   grn_operator logical_op;
3866   grn_obj wv;
3867   grn_obj index;
3868   grn_obj *query;
3869   grn_obj *args[GRN_SCAN_INFO_MAX_N_ARGS];
3870   int max_interval;
3871   int similarity_threshold;
3872   grn_obj scorers;
3873   grn_obj scorer_args_exprs;
3874   grn_obj scorer_args_expr_offsets;
3875   struct {
3876     grn_bool specified;
3877     int start;
3878   } position;
3879 };
3880 
3881 #define SI_FREE(si) do {\
3882   GRN_OBJ_FIN(ctx, &(si)->wv);\
3883   GRN_OBJ_FIN(ctx, &(si)->index);\
3884   GRN_OBJ_FIN(ctx, &(si)->scorers);\
3885   GRN_OBJ_FIN(ctx, &(si)->scorer_args_exprs);\
3886   GRN_OBJ_FIN(ctx, &(si)->scorer_args_expr_offsets);\
3887   GRN_FREE(si);\
3888 } while (0)
3889 
3890 #define SI_ALLOC_RAW(si, st) do {\
3891   if (((si) = GRN_MALLOCN(scan_info, 1))) {\
3892     GRN_INT32_INIT(&(si)->wv, GRN_OBJ_VECTOR);\
3893     GRN_PTR_INIT(&(si)->index, GRN_OBJ_VECTOR, GRN_ID_NIL);\
3894     (si)->logical_op = GRN_OP_OR;\
3895     (si)->flags = SCAN_PUSH;\
3896     (si)->nargs = 0;\
3897     (si)->max_interval = DEFAULT_MAX_INTERVAL;\
3898     (si)->similarity_threshold = DEFAULT_SIMILARITY_THRESHOLD;\
3899     (si)->start = (st);\
3900     (si)->query = NULL;\
3901     GRN_PTR_INIT(&(si)->scorers, GRN_OBJ_VECTOR, GRN_ID_NIL);\
3902     GRN_PTR_INIT(&(si)->scorer_args_exprs, GRN_OBJ_VECTOR, GRN_ID_NIL);\
3903     GRN_UINT32_INIT(&(si)->scorer_args_expr_offsets, GRN_OBJ_VECTOR);\
3904     (si)->position.specified = GRN_FALSE;\
3905     (si)->position.start = 0;\
3906   }\
3907 } while (0)
3908 
3909 #define SI_ALLOC(si, i, st) do {\
3910   SI_ALLOC_RAW(si, st);\
3911   if (!(si)) {\
3912     int j;\
3913     for (j = 0; j < i; j++) { SI_FREE(sis[j]); }\
3914     GRN_FREE(sis);\
3915     return NULL;\
3916   }\
3917 } while (0)
3918 
3919 static scan_info **
put_logical_op(grn_ctx * ctx,scan_info ** sis,int * ip,grn_operator op,int start)3920 put_logical_op(grn_ctx *ctx, scan_info **sis, int *ip, grn_operator op, int start)
3921 {
3922   int nparens = 1, ndifops = 0, i = *ip, j = i, r = 0;
3923   while (j--) {
3924     scan_info *s_ = sis[j];
3925     if (s_->flags & SCAN_POP) {
3926       ndifops++;
3927       nparens++;
3928     } else {
3929       if (s_->flags & SCAN_PUSH) {
3930         if (!(--nparens)) {
3931           if (!r) {
3932             if (ndifops) {
3933               if (j && op != GRN_OP_AND_NOT) {
3934                 nparens = 1;
3935                 ndifops = 0;
3936                 r = j;
3937               } else {
3938                 SI_ALLOC(s_, i, start);
3939                 s_->flags = SCAN_POP;
3940                 s_->logical_op = op;
3941                 sis[i++] = s_;
3942                 *ip = i;
3943                 break;
3944               }
3945             } else {
3946               s_->flags &= ~SCAN_PUSH;
3947               s_->logical_op = op;
3948               break;
3949             }
3950           } else {
3951             if (ndifops) {
3952               SI_ALLOC(s_, i, start);
3953               s_->flags = SCAN_POP;
3954               s_->logical_op = op;
3955               sis[i++] = s_;
3956               *ip = i;
3957             } else {
3958               s_->flags &= ~SCAN_PUSH;
3959               s_->logical_op = op;
3960               grn_memcpy(&sis[i], &sis[j], sizeof(scan_info *) * (r - j));
3961               grn_memmove(&sis[j], &sis[r], sizeof(scan_info *) * (i - r));
3962               grn_memcpy(&sis[i + j - r], &sis[i], sizeof(scan_info *) * (r - j));
3963             }
3964             break;
3965           }
3966         }
3967       } else {
3968         if ((op == GRN_OP_AND_NOT) || (op != s_->logical_op)) {
3969           ndifops++;
3970         }
3971       }
3972     }
3973   }
3974   if (j < 0) {
3975     ERR(GRN_INVALID_ARGUMENT, "unmatched nesting level");
3976     for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
3977     GRN_FREE(sis);
3978     return NULL;
3979   }
3980   return sis;
3981 }
3982 
3983 /* TODO: Remove me if nobody doesn't want to reuse the implementation again. */
3984 #if 0
3985 static const char *opstrs[] = {
3986   "PUSH",
3987   "POP",
3988   "NOP",
3989   "CALL",
3990   "INTERN",
3991   "GET_REF",
3992   "GET_VALUE",
3993   "AND",
3994   "AND_NOT",
3995   "OR",
3996   "ASSIGN",
3997   "STAR_ASSIGN",
3998   "SLASH_ASSIGN",
3999   "MOD_ASSIGN",
4000   "PLUS_ASSIGN",
4001   "MINUS_ASSIGN",
4002   "SHIFTL_ASSIGN",
4003   "SHIFTR_ASSIGN",
4004   "SHIFTRR_ASSIGN",
4005   "AND_ASSIGN",
4006   "XOR_ASSIGN",
4007   "OR_ASSIGN",
4008   "JUMP",
4009   "CJUMP",
4010   "COMMA",
4011   "BITWISE_OR",
4012   "BITWISE_XOR",
4013   "BITWISE_AND",
4014   "BITWISE_NOT",
4015   "EQUAL",
4016   "NOT_EQUAL",
4017   "LESS",
4018   "GREATER",
4019   "LESS_EQUAL",
4020   "GREATER_EQUAL",
4021   "IN",
4022   "MATCH",
4023   "NEAR",
4024   "NEAR2",
4025   "SIMILAR",
4026   "TERM_EXTRACT",
4027   "SHIFTL",
4028   "SHIFTR",
4029   "SHIFTRR",
4030   "PLUS",
4031   "MINUS",
4032   "STAR",
4033   "SLASH",
4034   "MOD",
4035   "DELETE",
4036   "INCR",
4037   "DECR",
4038   "INCR_POST",
4039   "DECR_POST",
4040   "NOT",
4041   "ADJUST",
4042   "EXACT",
4043   "LCP",
4044   "PARTIAL",
4045   "UNSPLIT",
4046   "PREFIX",
4047   "SUFFIX",
4048   "GEO_DISTANCE1",
4049   "GEO_DISTANCE2",
4050   "GEO_DISTANCE3",
4051   "GEO_DISTANCE4",
4052   "GEO_WITHINP5",
4053   "GEO_WITHINP6",
4054   "GEO_WITHINP8",
4055   "OBJ_SEARCH",
4056   "EXPR_GET_VAR",
4057   "TABLE_CREATE",
4058   "TABLE_SELECT",
4059   "TABLE_SORT",
4060   "TABLE_GROUP",
4061   "JSON_PUT"
4062 };
4063 
4064 static void
4065 put_value(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
4066 {
4067   int len;
4068   char namebuf[GRN_TABLE_MAX_KEY_SIZE];
4069   if ((len = grn_column_name(ctx, obj, namebuf, GRN_TABLE_MAX_KEY_SIZE))) {
4070     GRN_TEXT_PUT(ctx, buf, namebuf, len);
4071   } else {
4072     grn_text_otoj(ctx, buf, obj, NULL);
4073   }
4074 }
4075 
4076 static grn_rc
4077 grn_expr_inspect_internal(grn_ctx *ctx, grn_obj *buf, grn_obj *expr)
4078 {
4079   uint32_t i, j;
4080   grn_expr_var *var;
4081   grn_expr_code *code;
4082   grn_expr *e = (grn_expr *)expr;
4083   grn_hash *vars = grn_expr_get_vars(ctx, expr, &i);
4084   GRN_TEXT_PUTS(ctx, buf, "noname");
4085   GRN_TEXT_PUTC(ctx, buf, '(');
4086   {
4087     int i = 0;
4088     grn_obj *value;
4089     const char *name;
4090     uint32_t name_len;
4091     GRN_HASH_EACH(ctx, vars, id, &name, &name_len, &value, {
4092       if (i++) { GRN_TEXT_PUTC(ctx, buf, ','); }
4093       GRN_TEXT_PUT(ctx, buf, name, name_len);
4094       GRN_TEXT_PUTC(ctx, buf, ':');
4095       put_value(ctx, buf, value);
4096     });
4097   }
4098   GRN_TEXT_PUTC(ctx, buf, ')');
4099   GRN_TEXT_PUTC(ctx, buf, '{');
4100   for (j = 0, code = e->codes; j < e->codes_curr; j++, code++) {
4101     if (j) { GRN_TEXT_PUTC(ctx, buf, ','); }
4102     grn_text_itoa(ctx, buf, code->modify);
4103     if (code->op == GRN_OP_PUSH) {
4104       for (i = 0, var = e->vars; i < e->nvars; i++, var++) {
4105         if (&var->value == code->value) {
4106           GRN_TEXT_PUTC(ctx, buf, '?');
4107           if (var->name_size) {
4108             GRN_TEXT_PUT(ctx, buf, var->name, var->name_size);
4109           } else {
4110             grn_text_itoa(ctx, buf, (int)i);
4111           }
4112           break;
4113         }
4114       }
4115       if (i == e->nvars) {
4116         put_value(ctx, buf, code->value);
4117       }
4118     } else {
4119       if (code->value) {
4120         put_value(ctx, buf, code->value);
4121         GRN_TEXT_PUTC(ctx, buf, ' ');
4122       }
4123       GRN_TEXT_PUTS(ctx, buf, opstrs[code->op]);
4124     }
4125   }
4126   GRN_TEXT_PUTC(ctx, buf, '}');
4127   return GRN_SUCCESS;
4128 }
4129 
4130 #define EXPRLOG(name,expr) do {\
4131   grn_obj strbuf;\
4132   GRN_TEXT_INIT(&strbuf, 0);\
4133   grn_expr_inspect_internal(ctx, &strbuf, (expr));\
4134   GRN_TEXT_PUTC(ctx, &strbuf, '\0');\
4135   GRN_LOG(ctx, GRN_LOG_NOTICE, "%s=(%s)", (name), GRN_TEXT_VALUE(&strbuf));\
4136   GRN_OBJ_FIN(ctx, &strbuf);\
4137 } while (0)
4138 #endif
4139 
4140 
4141 static void
scan_info_put_index(grn_ctx * ctx,scan_info * si,grn_obj * index,uint32_t sid,int32_t weight,grn_obj * scorer,grn_obj * scorer_args_expr,uint32_t scorer_args_expr_offset)4142 scan_info_put_index(grn_ctx *ctx, scan_info *si,
4143                     grn_obj *index, uint32_t sid, int32_t weight,
4144                     grn_obj *scorer,
4145                     grn_obj *scorer_args_expr,
4146                     uint32_t scorer_args_expr_offset)
4147 {
4148   GRN_PTR_PUT(ctx, &si->index, index);
4149   GRN_UINT32_PUT(ctx, &si->wv, sid);
4150   GRN_INT32_PUT(ctx, &si->wv, weight);
4151   GRN_PTR_PUT(ctx, &si->scorers, scorer);
4152   GRN_PTR_PUT(ctx, &si->scorer_args_exprs, scorer_args_expr);
4153   GRN_UINT32_PUT(ctx, &si->scorer_args_expr_offsets, scorer_args_expr_offset);
4154   {
4155     int i, ni = (GRN_BULK_VSIZE(&si->index) / sizeof(grn_obj *)) - 1;
4156     grn_obj **pi = &GRN_PTR_VALUE_AT(&si->index, ni);
4157     for (i = 0; i < ni; i++, pi--) {
4158       if (index == pi[-1]) {
4159         if (i) {
4160           int32_t *pw = &GRN_INT32_VALUE_AT(&si->wv, (ni - i) * 2);
4161           grn_memmove(pw + 2, pw, sizeof(int32_t) * 2 * i);
4162           pw[0] = (int32_t) sid;
4163           pw[1] = weight;
4164           grn_memmove(pi + 1, pi, sizeof(grn_obj *) * i);
4165           pi[0] = index;
4166         }
4167         return;
4168       }
4169     }
4170   }
4171 }
4172 
4173 static int32_t
get_weight(grn_ctx * ctx,grn_expr_code * ec,uint32_t * offset)4174 get_weight(grn_ctx *ctx, grn_expr_code *ec, uint32_t *offset)
4175 {
4176   if (ec->modify == 2 && ec[2].op == GRN_OP_STAR &&
4177       ec[1].value && ec[1].value->header.type == GRN_BULK) {
4178     if (offset) {
4179       *offset = 2;
4180     }
4181     if (ec[1].value->header.domain == GRN_DB_INT32 ||
4182         ec[1].value->header.domain == GRN_DB_UINT32) {
4183       return GRN_INT32_VALUE(ec[1].value);
4184     } else {
4185       int32_t weight = 1;
4186       grn_obj weight_buffer;
4187       GRN_INT32_INIT(&weight_buffer, 0);
4188       if (!grn_obj_cast(ctx, ec[1].value, &weight_buffer, GRN_FALSE)) {
4189         weight = GRN_INT32_VALUE(&weight_buffer);
4190       }
4191       grn_obj_unlink(ctx, &weight_buffer);
4192       return weight;
4193     }
4194   } else {
4195     if (offset) {
4196       *offset = 0;
4197     }
4198     return 1;
4199   }
4200 }
4201 
4202 scan_info *
grn_scan_info_open(grn_ctx * ctx,int start)4203 grn_scan_info_open(grn_ctx *ctx, int start)
4204 {
4205   scan_info *si = GRN_MALLOCN(scan_info, 1);
4206 
4207   if (!si) {
4208     return NULL;
4209   }
4210 
4211   GRN_INT32_INIT(&si->wv, GRN_OBJ_VECTOR);
4212   GRN_PTR_INIT(&si->index, GRN_OBJ_VECTOR, GRN_ID_NIL);
4213   si->logical_op = GRN_OP_OR;
4214   si->flags = SCAN_PUSH;
4215   si->nargs = 0;
4216   si->max_interval = DEFAULT_MAX_INTERVAL;
4217   si->similarity_threshold = DEFAULT_SIMILARITY_THRESHOLD;
4218   si->start = start;
4219   GRN_PTR_INIT(&si->scorers, GRN_OBJ_VECTOR, GRN_ID_NIL);
4220   GRN_PTR_INIT(&si->scorer_args_exprs, GRN_OBJ_VECTOR, GRN_ID_NIL);
4221   GRN_UINT32_INIT(&si->scorer_args_expr_offsets, GRN_OBJ_VECTOR);
4222   si->position.specified = GRN_FALSE;
4223   si->position.start = 0;
4224 
4225   return si;
4226 }
4227 
4228 void
grn_scan_info_close(grn_ctx * ctx,scan_info * si)4229 grn_scan_info_close(grn_ctx *ctx, scan_info *si)
4230 {
4231   SI_FREE(si);
4232 }
4233 
4234 void
grn_scan_info_put_index(grn_ctx * ctx,scan_info * si,grn_obj * index,uint32_t sid,int32_t weight,grn_obj * scorer,grn_obj * scorer_args_expr,uint32_t scorer_args_expr_offset)4235 grn_scan_info_put_index(grn_ctx *ctx, scan_info *si,
4236                         grn_obj *index, uint32_t sid, int32_t weight,
4237                         grn_obj *scorer,
4238                         grn_obj *scorer_args_expr,
4239                         uint32_t scorer_args_expr_offset)
4240 {
4241   scan_info_put_index(ctx, si, index, sid, weight,
4242                       scorer,
4243                       scorer_args_expr,
4244                       scorer_args_expr_offset);
4245 }
4246 
4247 scan_info **
grn_scan_info_put_logical_op(grn_ctx * ctx,scan_info ** sis,int * ip,grn_operator op,int start)4248 grn_scan_info_put_logical_op(grn_ctx *ctx, scan_info **sis, int *ip,
4249                              grn_operator op, int start)
4250 {
4251   return put_logical_op(ctx, sis, ip, op, start);
4252 }
4253 
4254 int32_t
grn_expr_code_get_weight(grn_ctx * ctx,grn_expr_code * ec,uint32_t * offset)4255 grn_expr_code_get_weight(grn_ctx *ctx, grn_expr_code *ec, uint32_t *offset)
4256 {
4257   return get_weight(ctx, ec, offset);
4258 }
4259 
4260 int
grn_scan_info_get_flags(scan_info * si)4261 grn_scan_info_get_flags(scan_info *si)
4262 {
4263   return si->flags;
4264 }
4265 
4266 void
grn_scan_info_set_flags(scan_info * si,int flags)4267 grn_scan_info_set_flags(scan_info *si, int flags)
4268 {
4269   si->flags = flags;
4270 }
4271 
4272 grn_operator
grn_scan_info_get_logical_op(scan_info * si)4273 grn_scan_info_get_logical_op(scan_info *si)
4274 {
4275   return si->logical_op;
4276 }
4277 
4278 void
grn_scan_info_set_logical_op(scan_info * si,grn_operator logical_op)4279 grn_scan_info_set_logical_op(scan_info *si, grn_operator logical_op)
4280 {
4281   si->logical_op = logical_op;
4282 }
4283 
4284 grn_operator
grn_scan_info_get_op(scan_info * si)4285 grn_scan_info_get_op(scan_info *si)
4286 {
4287   return si->op;
4288 }
4289 
4290 void
grn_scan_info_set_op(scan_info * si,grn_operator op)4291 grn_scan_info_set_op(scan_info *si, grn_operator op)
4292 {
4293   si->op = op;
4294 }
4295 
4296 void
grn_scan_info_set_end(scan_info * si,uint32_t end)4297 grn_scan_info_set_end(scan_info *si, uint32_t end)
4298 {
4299   si->end = end;
4300 }
4301 
4302 void
grn_scan_info_set_query(scan_info * si,grn_obj * query)4303 grn_scan_info_set_query(scan_info *si, grn_obj *query)
4304 {
4305   si->query = query;
4306 }
4307 
4308 int
grn_scan_info_get_max_interval(scan_info * si)4309 grn_scan_info_get_max_interval(scan_info *si)
4310 {
4311   return si->max_interval;
4312 }
4313 
4314 void
grn_scan_info_set_max_interval(scan_info * si,int max_interval)4315 grn_scan_info_set_max_interval(scan_info *si, int max_interval)
4316 {
4317   si->max_interval = max_interval;
4318 }
4319 
4320 int
grn_scan_info_get_similarity_threshold(scan_info * si)4321 grn_scan_info_get_similarity_threshold(scan_info *si)
4322 {
4323   return si->similarity_threshold;
4324 }
4325 
4326 void
grn_scan_info_set_similarity_threshold(scan_info * si,int similarity_threshold)4327 grn_scan_info_set_similarity_threshold(scan_info *si, int similarity_threshold)
4328 {
4329   si->similarity_threshold = similarity_threshold;
4330 }
4331 
4332 grn_bool
grn_scan_info_push_arg(scan_info * si,grn_obj * arg)4333 grn_scan_info_push_arg(scan_info *si, grn_obj *arg)
4334 {
4335   if (si->nargs >= GRN_SCAN_INFO_MAX_N_ARGS) {
4336     return GRN_FALSE;
4337   }
4338 
4339   si->args[si->nargs++] = arg;
4340   return GRN_TRUE;
4341 }
4342 
4343 grn_obj *
grn_scan_info_get_arg(grn_ctx * ctx,scan_info * si,int i)4344 grn_scan_info_get_arg(grn_ctx *ctx, scan_info *si, int i)
4345 {
4346   if (i >= si->nargs) {
4347     return NULL;
4348   }
4349   return si->args[i];
4350 }
4351 
4352 int
grn_scan_info_get_start_position(scan_info * si)4353 grn_scan_info_get_start_position(scan_info *si)
4354 {
4355   return si->position.start;
4356 }
4357 
4358 void
grn_scan_info_set_start_position(scan_info * si,int start)4359 grn_scan_info_set_start_position(scan_info *si, int start)
4360 {
4361   si->position.specified = GRN_TRUE;
4362   si->position.start = start;
4363 }
4364 
4365 void
grn_scan_info_reset_position(scan_info * si)4366 grn_scan_info_reset_position(scan_info *si)
4367 {
4368   si->position.specified = GRN_FALSE;
4369 }
4370 
4371 static uint32_t
scan_info_build_match_expr_codes_find_index(grn_ctx * ctx,scan_info * si,grn_expr * expr,uint32_t i,grn_obj ** index,int * sid)4372 scan_info_build_match_expr_codes_find_index(grn_ctx *ctx, scan_info *si,
4373                                             grn_expr *expr, uint32_t i,
4374                                             grn_obj **index,
4375                                             int *sid)
4376 {
4377   grn_expr_code *ec;
4378   uint32_t offset = 1;
4379   grn_index_datum index_datum;
4380   unsigned int n_index_data = 0;
4381 
4382   ec = &(expr->codes[i]);
4383   switch (ec->value->header.type) {
4384   case GRN_ACCESSOR :
4385     n_index_data = grn_column_find_index_data(ctx, ec->value, si->op,
4386                                               &index_datum, 1);
4387     if (n_index_data > 0) {
4388       grn_accessor *a = (grn_accessor *)(ec->value);
4389       *sid = index_datum.section;
4390       if (a->next && a->obj != index_datum.index) {
4391         *index = ec->value;
4392       } else {
4393         *index = index_datum.index;
4394       }
4395     }
4396     break;
4397   case GRN_COLUMN_FIX_SIZE :
4398   case GRN_COLUMN_VAR_SIZE :
4399     n_index_data = grn_column_find_index_data(ctx, ec->value, si->op,
4400                                               &index_datum, 1);
4401     if (n_index_data > 0) {
4402       *index = index_datum.index;
4403       *sid = index_datum.section;
4404     }
4405     break;
4406   case GRN_COLUMN_INDEX :
4407     {
4408       uint32_t n_rest_codes;
4409 
4410       *index = ec->value;
4411 
4412       n_rest_codes = expr->codes_curr - i;
4413       if (n_rest_codes >= 2 &&
4414           ec[1].value &&
4415           (ec[1].value->header.domain == GRN_DB_INT32 ||
4416            ec[1].value->header.domain == GRN_DB_UINT32) &&
4417           ec[2].op == GRN_OP_GET_MEMBER) {
4418         if (ec[1].value->header.domain == GRN_DB_INT32) {
4419           *sid = GRN_INT32_VALUE(ec[1].value) + 1;
4420         } else {
4421           *sid = GRN_UINT32_VALUE(ec[1].value) + 1;
4422         }
4423         offset += 2;
4424       }
4425     }
4426     break;
4427   default :
4428     break;
4429   }
4430 
4431   return offset;
4432 }
4433 
4434 static uint32_t
scan_info_build_match_expr_codes(grn_ctx * ctx,scan_info * si,grn_expr * expr,uint32_t i,int32_t weight)4435 scan_info_build_match_expr_codes(grn_ctx *ctx,
4436                                  scan_info *si,
4437                                  grn_expr *expr,
4438                                  uint32_t i,
4439                                  int32_t weight)
4440 {
4441   grn_expr_code *ec;
4442   grn_obj *index = NULL;
4443   int sid = 0;
4444   uint32_t offset = 0;
4445 
4446   ec = &(expr->codes[i]);
4447   if (!ec->value) {
4448     return i + 1;
4449   }
4450 
4451   switch (ec->value->header.type) {
4452   case GRN_ACCESSOR :
4453   case GRN_COLUMN_FIX_SIZE :
4454   case GRN_COLUMN_VAR_SIZE :
4455   case GRN_COLUMN_INDEX :
4456     offset = scan_info_build_match_expr_codes_find_index(ctx, si, expr, i,
4457                                                          &index, &sid);
4458     i += offset - 1;
4459     if (index) {
4460       if (ec->value->header.type == GRN_ACCESSOR) {
4461         si->flags |= SCAN_ACCESSOR;
4462       }
4463       scan_info_put_index(ctx, si, index, sid,
4464                           get_weight(ctx, &(expr->codes[i]), &offset) + weight,
4465                           NULL, NULL, 0);
4466       i += offset;
4467     }
4468     break;
4469   case GRN_PROC :
4470     if (!grn_obj_is_scorer_proc(ctx, ec->value)) {
4471       grn_obj inspected;
4472       GRN_TEXT_INIT(&inspected, 0);
4473       grn_inspect(ctx, &inspected, ec->value);
4474       ERR(GRN_INVALID_ARGUMENT,
4475           "procedure must be scorer: <%.*s>",
4476           (int)GRN_TEXT_LEN(&inspected),
4477           GRN_TEXT_VALUE(&inspected));
4478       GRN_OBJ_FIN(ctx, &inspected);
4479       return expr->codes_curr;
4480     }
4481     i++;
4482     offset = scan_info_build_match_expr_codes_find_index(ctx, si, expr, i,
4483                                                          &index, &sid);
4484     i += offset;
4485     if (index) {
4486       uint32_t scorer_args_expr_offset = 0;
4487       if (expr->codes[i].op != GRN_OP_CALL) {
4488         scorer_args_expr_offset = i;
4489       }
4490       while (i < expr->codes_curr && expr->codes[i].op != GRN_OP_CALL) {
4491         i++;
4492       }
4493       scan_info_put_index(ctx, si, index, sid,
4494                           get_weight(ctx, &(expr->codes[i]), &offset) + weight,
4495                           ec->value,
4496                           (grn_obj *)expr,
4497                           scorer_args_expr_offset);
4498       i += offset;
4499     }
4500     break;
4501   default :
4502     {
4503       char name[GRN_TABLE_MAX_KEY_SIZE];
4504       int name_size;
4505       name_size = grn_obj_name(ctx, ec->value, name, GRN_TABLE_MAX_KEY_SIZE);
4506       ERR(GRN_INVALID_ARGUMENT,
4507           "invalid match target: <%.*s>",
4508           name_size, name);
4509       return expr->codes_curr;
4510     }
4511     break;
4512   }
4513 
4514   return i + 1;
4515 }
4516 
4517 static void
scan_info_build_match_expr(grn_ctx * ctx,scan_info * si,grn_expr * expr,int32_t weight)4518 scan_info_build_match_expr(grn_ctx *ctx,
4519                            scan_info *si,
4520                            grn_expr *expr,
4521                            int32_t weight)
4522 {
4523   uint32_t i;
4524   i = 0;
4525   while (i < expr->codes_curr) {
4526     i = scan_info_build_match_expr_codes(ctx, si, expr, i, weight);
4527   }
4528 }
4529 
4530 static grn_bool
is_index_searchable_regexp(grn_ctx * ctx,grn_obj * regexp)4531 is_index_searchable_regexp(grn_ctx *ctx, grn_obj *regexp)
4532 {
4533   const char *regexp_raw;
4534   const char *regexp_raw_end;
4535   grn_bool escaping = GRN_FALSE;
4536   grn_bool dot = GRN_FALSE;
4537 
4538   if (!(regexp->header.domain == GRN_DB_SHORT_TEXT ||
4539         regexp->header.domain == GRN_DB_TEXT ||
4540         regexp->header.domain == GRN_DB_LONG_TEXT)) {
4541     return GRN_FALSE;
4542   }
4543 
4544   regexp_raw = GRN_TEXT_VALUE(regexp);
4545   regexp_raw_end = regexp_raw + GRN_TEXT_LEN(regexp);
4546 
4547   while (regexp_raw < regexp_raw_end) {
4548     unsigned int char_len;
4549 
4550     char_len = grn_charlen(ctx, regexp_raw, regexp_raw_end);
4551     if (char_len == 0) {
4552       return GRN_FALSE;
4553     }
4554 
4555     if (char_len == 1) {
4556       if (escaping) {
4557         escaping = GRN_FALSE;
4558         switch (regexp_raw[0]) {
4559         case 'Z' :
4560         case 'b' :
4561         case 'B' :
4562         case 'd' :
4563         case 'D' :
4564         case 'h' :
4565         case 'H' :
4566         case 'p' :
4567         case 's' :
4568         case 'S' :
4569         case 'w' :
4570         case 'W' :
4571         case 'X' :
4572         case 'k' :
4573         case 'g' :
4574         case '1' :
4575         case '2' :
4576         case '3' :
4577         case '4' :
4578         case '5' :
4579         case '6' :
4580         case '7' :
4581         case '8' :
4582         case '9' :
4583           return GRN_FALSE;
4584         default :
4585           break;
4586         }
4587       } else {
4588         switch (regexp_raw[0]) {
4589         case '.' :
4590           escaping = GRN_FALSE;
4591           if (dot) {
4592             return GRN_FALSE;
4593           }
4594           dot = GRN_TRUE;
4595           break;
4596         case '*' :
4597           escaping = GRN_FALSE;
4598           if (!dot) {
4599             return GRN_FALSE;
4600           }
4601           if (!grn_scan_info_regexp_dot_asterisk_enable)  {
4602             return GRN_FALSE;
4603           }
4604           dot = GRN_FALSE;
4605           break;
4606         case '[' :
4607         case ']' :
4608         case '|' :
4609         case '?' :
4610         case '+' :
4611         case '{' :
4612         case '}' :
4613         case '^' :
4614         case '$' :
4615         case '(' :
4616         case ')' :
4617           escaping = GRN_FALSE;
4618           return GRN_FALSE;
4619         case '\\' :
4620           if (dot) {
4621             return GRN_FALSE;
4622           }
4623           escaping = GRN_TRUE;
4624           break;
4625         default :
4626           if (dot) {
4627             return GRN_FALSE;
4628           }
4629           escaping = GRN_FALSE;
4630           break;
4631         }
4632       }
4633     } else {
4634       escaping = GRN_FALSE;
4635     }
4636 
4637     regexp_raw += char_len;
4638   }
4639 
4640   return GRN_TRUE;
4641 }
4642 
4643 static void
scan_info_build_match(grn_ctx * ctx,scan_info * si,int32_t weight)4644 scan_info_build_match(grn_ctx *ctx, scan_info *si, int32_t weight)
4645 {
4646   grn_obj **p, **pe;
4647 
4648   if (si->op == GRN_OP_REGEXP) {
4649     p = si->args;
4650     pe = si->args + si->nargs;
4651     for (; p < pe; p++) {
4652       if ((*p)->header.type == GRN_BULK &&
4653           !is_index_searchable_regexp(ctx, *p)) {
4654         return;
4655       }
4656     }
4657   }
4658 
4659   p = si->args;
4660   pe = si->args + si->nargs;
4661   for (; p < pe; p++) {
4662     if ((*p)->header.type == GRN_EXPR) {
4663       scan_info_build_match_expr(ctx, si, (grn_expr *)(*p), weight);
4664     } else if ((*p)->header.type == GRN_COLUMN_INDEX) {
4665       scan_info_put_index(ctx, si, *p, 0, 1 + weight, NULL, NULL, 0);
4666     } else if (grn_obj_is_proc(ctx, *p)) {
4667       break;
4668     } else if (GRN_DB_OBJP(*p)) {
4669       grn_index_datum index_datum;
4670       unsigned int n_index_data;
4671       n_index_data = grn_column_find_index_data(ctx, *p, si->op,
4672                                                 &index_datum, 1);
4673       if (n_index_data > 0) {
4674         scan_info_put_index(ctx, si,
4675                             index_datum.index, index_datum.section, 1 + weight,
4676                             NULL, NULL, 0);
4677       }
4678     } else if (GRN_ACCESSORP(*p)) {
4679       grn_index_datum index_datum;
4680       unsigned int n_index_data;
4681       si->flags |= SCAN_ACCESSOR;
4682       n_index_data = grn_column_find_index_data(ctx, *p, si->op,
4683                                                 &index_datum, 1);
4684       if (n_index_data > 0) {
4685         grn_obj *index;
4686         if (((grn_accessor *)(*p))->next) {
4687           index = *p;
4688         } else {
4689           index = index_datum.index;
4690         }
4691         scan_info_put_index(ctx, si,
4692                             index, index_datum.section, 1 + weight,
4693                             NULL, NULL, 0);
4694       }
4695     } else {
4696       switch (si->op) {
4697       case GRN_OP_NEAR :
4698       case GRN_OP_NEAR2 :
4699         if (si->nargs == 3 &&
4700             *p == si->args[2] &&
4701             (*p)->header.domain == GRN_DB_INT32) {
4702           si->max_interval = GRN_INT32_VALUE(*p);
4703         } else {
4704           si->query = *p;
4705         }
4706         break;
4707       case GRN_OP_SIMILAR :
4708         if (si->nargs == 3 &&
4709             *p == si->args[2] &&
4710             (*p)->header.domain == GRN_DB_INT32) {
4711           si->similarity_threshold = GRN_INT32_VALUE(*p);
4712         } else {
4713           si->query = *p;
4714         }
4715         break;
4716       default :
4717         si->query = *p;
4718         break;
4719       }
4720     }
4721   }
4722 }
4723 
4724 static grn_bool
grn_scan_info_build_full_not(grn_ctx * ctx,scan_info ** sis,int * i,grn_expr_code * codes,grn_expr_code * code,grn_expr_code * code_end,grn_operator * next_code_op)4725 grn_scan_info_build_full_not(grn_ctx *ctx,
4726                              scan_info **sis,
4727                              int *i,
4728                              grn_expr_code *codes,
4729                              grn_expr_code *code,
4730                              grn_expr_code *code_end,
4731                              grn_operator *next_code_op)
4732 {
4733   scan_info *last_si;
4734 
4735   if (*i == 0) {
4736     return GRN_TRUE;
4737   }
4738 
4739   last_si = sis[*i - 1];
4740   switch (last_si->op) {
4741   case GRN_OP_LESS :
4742     last_si->op = GRN_OP_GREATER_EQUAL;
4743     last_si->end++;
4744     break;
4745   case GRN_OP_LESS_EQUAL :
4746     last_si->op = GRN_OP_GREATER;
4747     last_si->end++;
4748     break;
4749   case GRN_OP_GREATER :
4750     last_si->op = GRN_OP_LESS_EQUAL;
4751     last_si->end++;
4752     break;
4753   case GRN_OP_GREATER_EQUAL :
4754     last_si->op = GRN_OP_LESS;
4755     last_si->end++;
4756     break;
4757   case GRN_OP_NOT_EQUAL :
4758     last_si->op = GRN_OP_EQUAL;
4759     last_si->end++;
4760     break;
4761   default :
4762     if (*i == 1) {
4763       if (GRN_BULK_VSIZE(&(last_si->index)) > 0) {
4764         scan_info *all_records_si = NULL;
4765         SI_ALLOC_RAW(all_records_si, 0);
4766         if (!all_records_si) {
4767           return GRN_FALSE;
4768         }
4769         all_records_si->op = GRN_OP_CALL;
4770         all_records_si->args[all_records_si->nargs++] =
4771           grn_ctx_get(ctx, "all_records", -1);
4772         last_si->logical_op = GRN_OP_AND_NOT;
4773         last_si->flags &= ~SCAN_PUSH;
4774         sis[*i] = sis[*i - 1];
4775         sis[*i - 1] = all_records_si;
4776         (*i)++;
4777       } else {
4778         if (last_si->op == GRN_OP_EQUAL) {
4779           last_si->op = GRN_OP_NOT_EQUAL;
4780           last_si->end++;
4781         } else {
4782           return GRN_FALSE;
4783         }
4784       }
4785     } else {
4786       grn_expr_code *next_code = code + 1;
4787 
4788       if (next_code >= code_end) {
4789         return GRN_FALSE;
4790       }
4791 
4792       switch (next_code->op) {
4793       case GRN_OP_AND :
4794         *next_code_op = GRN_OP_AND_NOT;
4795         break;
4796       case GRN_OP_AND_NOT :
4797         *next_code_op = GRN_OP_AND;
4798         break;
4799       case GRN_OP_OR :
4800         {
4801           scan_info *all_records_si = NULL;
4802           SI_ALLOC_RAW(all_records_si, 0);
4803           if (!all_records_si) {
4804             return GRN_FALSE;
4805           }
4806           all_records_si->op = GRN_OP_CALL;
4807           all_records_si->args[all_records_si->nargs++] =
4808             grn_ctx_get(ctx, "all_records", -1);
4809           sis[*i] = sis[*i - 1];
4810           sis[*i - 1] = all_records_si;
4811           (*i)++;
4812           put_logical_op(ctx, sis, i, GRN_OP_AND_NOT, code - codes);
4813         }
4814         break;
4815       default :
4816         return GRN_FALSE;
4817         break;
4818       }
4819     }
4820   }
4821 
4822   return GRN_TRUE;
4823 }
4824 
4825 static scan_info **
grn_scan_info_build_full(grn_ctx * ctx,grn_obj * expr,int * n,grn_operator op,grn_bool record_exist)4826 grn_scan_info_build_full(grn_ctx *ctx, grn_obj *expr, int *n,
4827                          grn_operator op, grn_bool record_exist)
4828 {
4829   grn_obj *var;
4830   scan_stat stat;
4831   int i, m = 0, o = 0;
4832   int n_nots = 0;
4833   scan_info **sis, *si = NULL;
4834   grn_expr_code *c, *ce;
4835   grn_expr *e = (grn_expr *)expr;
4836   grn_operator next_code_op;
4837 
4838   if (!(var = grn_expr_get_var_by_offset(ctx, expr, 0))) { return NULL; }
4839   for (stat = SCAN_START, c = e->codes, ce = &e->codes[e->codes_curr]; c < ce; c++) {
4840     switch (c->op) {
4841     case GRN_OP_MATCH :
4842     case GRN_OP_NEAR :
4843     case GRN_OP_NEAR2 :
4844     case GRN_OP_SIMILAR :
4845     case GRN_OP_PREFIX :
4846     case GRN_OP_SUFFIX :
4847     case GRN_OP_EQUAL :
4848     case GRN_OP_NOT_EQUAL :
4849     case GRN_OP_LESS :
4850     case GRN_OP_GREATER :
4851     case GRN_OP_LESS_EQUAL :
4852     case GRN_OP_GREATER_EQUAL :
4853     case GRN_OP_GEO_WITHINP5 :
4854     case GRN_OP_GEO_WITHINP6 :
4855     case GRN_OP_GEO_WITHINP8 :
4856     case GRN_OP_TERM_EXTRACT :
4857     case GRN_OP_REGEXP :
4858       if (stat < SCAN_COL1 || SCAN_CONST < stat) { return NULL; }
4859       stat = SCAN_START;
4860       m++;
4861       break;
4862     case GRN_OP_BITWISE_OR :
4863     case GRN_OP_BITWISE_XOR :
4864     case GRN_OP_BITWISE_AND :
4865     case GRN_OP_BITWISE_NOT :
4866     case GRN_OP_SHIFTL :
4867     case GRN_OP_SHIFTR :
4868     case GRN_OP_SHIFTRR :
4869     case GRN_OP_PLUS :
4870     case GRN_OP_MINUS :
4871     case GRN_OP_STAR :
4872     case GRN_OP_MOD :
4873       if (stat < SCAN_COL1 || SCAN_CONST < stat) { return NULL; }
4874       stat = SCAN_START;
4875       if (m != o + 1) { return NULL; }
4876       break;
4877     case GRN_OP_AND :
4878     case GRN_OP_OR :
4879     case GRN_OP_AND_NOT :
4880     case GRN_OP_ADJUST :
4881       switch (stat) {
4882       case SCAN_START :
4883         o++;
4884         if (o >= m) { return NULL; }
4885         break;
4886       case SCAN_CONST :
4887         o++;
4888         m++;
4889         if (o >= m) { return NULL; }
4890         stat = SCAN_START;
4891         break;
4892       default :
4893         return NULL;
4894         break;
4895       }
4896       break;
4897     case GRN_OP_PUSH :
4898       {
4899         grn_bool is_completed_term = GRN_FALSE;
4900         if (c->modify > 0) {
4901           switch ((c + c->modify)->op) {
4902           case GRN_OP_AND :
4903           case GRN_OP_OR :
4904           case GRN_OP_AND_NOT :
4905           case GRN_OP_ADJUST :
4906             is_completed_term = GRN_TRUE;
4907             break;
4908           default :
4909             is_completed_term = GRN_FALSE;
4910             break;
4911           }
4912         }
4913         if (is_completed_term) {
4914           m++;
4915           stat = SCAN_START;
4916         } else {
4917           stat = (c->value == var) ? SCAN_VAR : SCAN_CONST;
4918         }
4919       }
4920       break;
4921     case GRN_OP_GET_VALUE :
4922       switch (stat) {
4923       case SCAN_START :
4924       case SCAN_CONST :
4925       case SCAN_VAR :
4926         stat = SCAN_COL1;
4927         break;
4928       case SCAN_COL1 :
4929         stat = SCAN_COL2;
4930         break;
4931       case SCAN_COL2 :
4932         break;
4933       default :
4934         return NULL;
4935         break;
4936       }
4937       break;
4938     case GRN_OP_CALL :
4939       if ((c->flags & GRN_EXPR_CODE_RELATIONAL_EXPRESSION) || c + 1 == ce) {
4940         stat = SCAN_START;
4941         m++;
4942       } else {
4943         stat = SCAN_COL2;
4944       }
4945       break;
4946     case GRN_OP_GET_REF :
4947       switch (stat) {
4948       case SCAN_START :
4949         stat = SCAN_COL1;
4950         break;
4951       default :
4952         return NULL;
4953         break;
4954       }
4955       break;
4956     case GRN_OP_GET_MEMBER :
4957       switch (stat) {
4958       case SCAN_CONST :
4959         {
4960           grn_expr_code *prev_c = c - 1;
4961           if (prev_c->value->header.domain < GRN_DB_INT8 ||
4962               prev_c->value->header.domain > GRN_DB_UINT64) {
4963             return NULL;
4964           }
4965         }
4966         stat = SCAN_COL1;
4967         break;
4968       default :
4969         return NULL;
4970         break;
4971       }
4972       break;
4973     case GRN_OP_NOT :
4974       n_nots++;
4975       break;
4976     default :
4977       return NULL;
4978       break;
4979     }
4980   }
4981   if (stat || m != o + 1) { return NULL; }
4982   if (!(sis = GRN_MALLOCN(scan_info *, m + m + o + n_nots))) { return NULL; }
4983 
4984   next_code_op = -1;
4985   for (i = 0, stat = SCAN_START, c = e->codes, ce = &e->codes[e->codes_curr]; c < ce; c++) {
4986     grn_operator code_op;
4987     if (next_code_op == (grn_operator)-1) {
4988       code_op = c->op;
4989     } else {
4990       code_op = next_code_op;
4991       next_code_op = -1;
4992     }
4993     switch (code_op) {
4994     case GRN_OP_MATCH :
4995     case GRN_OP_NEAR :
4996     case GRN_OP_NEAR2 :
4997     case GRN_OP_SIMILAR :
4998     case GRN_OP_PREFIX :
4999     case GRN_OP_SUFFIX :
5000     case GRN_OP_EQUAL :
5001     case GRN_OP_NOT_EQUAL :
5002     case GRN_OP_LESS :
5003     case GRN_OP_GREATER :
5004     case GRN_OP_LESS_EQUAL :
5005     case GRN_OP_GREATER_EQUAL :
5006     case GRN_OP_GEO_WITHINP5 :
5007     case GRN_OP_GEO_WITHINP6 :
5008     case GRN_OP_GEO_WITHINP8 :
5009     case GRN_OP_TERM_EXTRACT :
5010     case GRN_OP_REGEXP :
5011       stat = SCAN_START;
5012       si->op = code_op;
5013       si->end = c - e->codes;
5014       sis[i++] = si;
5015       {
5016         int32_t weight = 0;
5017         if (c->value && c->value->header.domain == GRN_DB_INT32) {
5018           weight = GRN_INT32_VALUE(c->value);
5019         }
5020         scan_info_build_match(ctx, si, weight);
5021       }
5022       if (ctx->rc != GRN_SUCCESS) {
5023         int j;
5024         for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
5025         GRN_FREE(sis);
5026         return NULL;
5027       }
5028       si = NULL;
5029       break;
5030     case GRN_OP_AND :
5031     case GRN_OP_OR :
5032     case GRN_OP_AND_NOT :
5033     case GRN_OP_ADJUST :
5034       if (stat == SCAN_CONST) {
5035         si->op = GRN_OP_PUSH;
5036         si->end = si->start;
5037         sis[i++] = si;
5038         si = NULL;
5039       }
5040       if (!put_logical_op(ctx, sis, &i, code_op, c - e->codes)) { return NULL; }
5041       stat = SCAN_START;
5042       break;
5043     case GRN_OP_PUSH :
5044       if (!si) { SI_ALLOC(si, i, c - e->codes); }
5045       if (c->value == var) {
5046         stat = SCAN_VAR;
5047       } else {
5048         if (si->nargs < GRN_SCAN_INFO_MAX_N_ARGS) {
5049           si->args[si->nargs++] = c->value;
5050         }
5051         if (stat == SCAN_START) { si->flags |= SCAN_PRE_CONST; }
5052         stat = SCAN_CONST;
5053       }
5054       if (c->modify > 0) {
5055         grn_bool is_completed_term = GRN_FALSE;
5056         switch ((c + c->modify)->op) {
5057         case GRN_OP_AND :
5058         case GRN_OP_OR :
5059         case GRN_OP_AND_NOT :
5060         case GRN_OP_ADJUST :
5061           is_completed_term = GRN_TRUE;
5062           break;
5063         default :
5064           is_completed_term = GRN_FALSE;
5065           break;
5066         }
5067         if (is_completed_term) {
5068           si->op = GRN_OP_PUSH;
5069           si->end = si->start;
5070           sis[i++] = si;
5071           si = NULL;
5072           stat = SCAN_START;
5073         }
5074       }
5075       break;
5076     case GRN_OP_GET_VALUE :
5077       switch (stat) {
5078       case SCAN_START :
5079         if (!si) { SI_ALLOC(si, i, c - e->codes); }
5080         // fallthru
5081       case SCAN_CONST :
5082       case SCAN_VAR :
5083         stat = SCAN_COL1;
5084         if (si->nargs < GRN_SCAN_INFO_MAX_N_ARGS) {
5085           si->args[si->nargs++] = c->value;
5086         }
5087         break;
5088       case SCAN_COL1 :
5089         {
5090           int j;
5091           grn_obj inspected;
5092           GRN_TEXT_INIT(&inspected, 0);
5093           GRN_TEXT_PUTS(ctx, &inspected, "<");
5094           grn_inspect_name(ctx, &inspected, c->value);
5095           GRN_TEXT_PUTS(ctx, &inspected, ">: <");
5096           grn_inspect(ctx, &inspected, expr);
5097           GRN_TEXT_PUTS(ctx, &inspected, ">");
5098           ERR(GRN_INVALID_ARGUMENT,
5099               "invalid expression: can't use column as a value: %.*s",
5100               (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
5101           GRN_OBJ_FIN(ctx, &inspected);
5102           SI_FREE(si);
5103           for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
5104           GRN_FREE(sis);
5105           return NULL;
5106         }
5107         stat = SCAN_COL2;
5108         break;
5109       case SCAN_COL2 :
5110         break;
5111       default :
5112         break;
5113       }
5114       break;
5115     case GRN_OP_CALL :
5116       if (!si) { SI_ALLOC(si, i, c - e->codes); }
5117       if ((c->flags & GRN_EXPR_CODE_RELATIONAL_EXPRESSION) || c + 1 == ce) {
5118         stat = SCAN_START;
5119         si->op = code_op;
5120         si->end = c - e->codes;
5121         sis[i++] = si;
5122         /* better index resolving framework for functions should be implemented */
5123         if (grn_obj_is_selector_proc(ctx, si->args[0])) {
5124           grn_obj *selector;
5125           grn_obj **p;
5126           grn_obj **pe;
5127           grn_operator selector_op;
5128 
5129           selector = si->args[0];
5130           p = si->args + 1;
5131           pe = si->args + si->nargs;
5132           selector_op = grn_proc_get_selector_operator(ctx, selector);
5133           for (; p < pe; p++) {
5134             if (GRN_DB_OBJP(*p)) {
5135               grn_index_datum index_datum;
5136               unsigned int n_index_data;
5137               n_index_data = grn_column_find_index_data(ctx, *p, selector_op,
5138                                                         &index_datum, 1);
5139               if (n_index_data > 0) {
5140                 scan_info_put_index(ctx, si,
5141                                     index_datum.index, index_datum.section, 1,
5142                                     NULL, NULL, 0);
5143               }
5144             } else if (GRN_ACCESSORP(*p)) {
5145               grn_index_datum index_datum;
5146               unsigned int n_index_data;
5147               si->flags |= SCAN_ACCESSOR;
5148               n_index_data = grn_column_find_index_data(ctx, *p, selector_op,
5149                                                         &index_datum, 1);
5150               if (n_index_data > 0) {
5151                 scan_info_put_index(ctx, si,
5152                                     index_datum.index, index_datum.section, 1,
5153                                     NULL, NULL, 0);
5154               }
5155             } else {
5156               si->query = *p;
5157             }
5158           }
5159         }
5160         si = NULL;
5161       } else {
5162         stat = SCAN_COL2;
5163       }
5164       break;
5165     case GRN_OP_GET_REF :
5166       switch (stat) {
5167       case SCAN_START :
5168         if (!si) { SI_ALLOC(si, i, c - e->codes); }
5169         stat = SCAN_COL1;
5170         if (si->nargs < GRN_SCAN_INFO_MAX_N_ARGS) {
5171           si->args[si->nargs++] = c->value;
5172         }
5173         break;
5174       default :
5175         break;
5176       }
5177       break;
5178     case GRN_OP_GET_MEMBER :
5179       {
5180         grn_obj *start_position;
5181         grn_obj buffer;
5182         start_position = si->args[--si->nargs];
5183         GRN_INT32_INIT(&buffer, 0);
5184         grn_obj_cast(ctx, start_position, &buffer, GRN_FALSE);
5185         grn_scan_info_set_start_position(si, GRN_INT32_VALUE(&buffer));
5186         GRN_OBJ_FIN(ctx, &buffer);
5187       }
5188       stat = SCAN_COL1;
5189       break;
5190     case GRN_OP_NOT :
5191       {
5192         grn_bool valid;
5193         valid = grn_scan_info_build_full_not(ctx,
5194                                              sis,
5195                                              &i,
5196                                              e->codes,
5197                                              c,
5198                                              ce,
5199                                              &next_code_op);
5200         if (!valid) {
5201           int j;
5202           for (j = 0; j < i; j++) {
5203             SI_FREE(sis[j]);
5204           }
5205           GRN_FREE(sis);
5206           return NULL;
5207         }
5208       }
5209       break;
5210     default :
5211       break;
5212     }
5213   }
5214   if (op == GRN_OP_OR && !record_exist) {
5215     // for debug
5216     if (!(sis[0]->flags & SCAN_PUSH) || (sis[0]->logical_op != op)) {
5217       int j;
5218       ERR(GRN_INVALID_ARGUMENT, "invalid expr");
5219       for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
5220       GRN_FREE(sis);
5221       return NULL;
5222     } else {
5223       sis[0]->flags &= ~SCAN_PUSH;
5224       sis[0]->logical_op = op;
5225     }
5226   } else {
5227     if (!put_logical_op(ctx, sis, &i, op, c - e->codes)) { return NULL; }
5228   }
5229   *n = i;
5230   return sis;
5231 }
5232 
5233 static scan_info **
grn_scan_info_build_simple_open(grn_ctx * ctx,int * n,grn_operator logical_op)5234 grn_scan_info_build_simple_open(grn_ctx *ctx, int *n, grn_operator logical_op)
5235 {
5236   scan_info **sis;
5237   scan_info *si;
5238 
5239   sis = GRN_MALLOCN(scan_info *, 1);
5240   if (!sis) {
5241     ERR(GRN_NO_MEMORY_AVAILABLE,
5242         "[scan_info][build] failed to allocate memory for scan_info **");
5243     return NULL;
5244   }
5245 
5246   si = grn_scan_info_open(ctx, 0);
5247   if (!si) {
5248     ERR(GRN_NO_MEMORY_AVAILABLE,
5249         "[scan_info][build] failed to allocate memory for scan_info *");
5250     GRN_FREE(sis);
5251     return NULL;
5252   }
5253 
5254   si->flags &= ~SCAN_PUSH;
5255   si->logical_op = logical_op;
5256 
5257   sis[0] = si;
5258   *n = 1;
5259 
5260   return sis;
5261 }
5262 
5263 static scan_info **
grn_scan_info_build_simple_value(grn_ctx * ctx,grn_obj * expr,int * n,grn_operator logical_op,grn_bool record_exist)5264 grn_scan_info_build_simple_value(grn_ctx *ctx,
5265                                  grn_obj *expr,
5266                                  int *n,
5267                                  grn_operator logical_op,
5268                                  grn_bool record_exist)
5269 {
5270   grn_expr *e = (grn_expr *)expr;
5271   scan_info **sis;
5272   scan_info *si;
5273   grn_expr_code *target = e->codes;
5274 
5275   switch (target->op) {
5276   case GRN_OP_PUSH :
5277   case GRN_OP_GET_VALUE :
5278     break;
5279   default :
5280     return NULL;
5281     break;
5282   }
5283 
5284   sis = grn_scan_info_build_simple_open(ctx, n, logical_op);
5285   if (!sis) {
5286     return NULL;
5287   }
5288 
5289   si = sis[0];
5290   si->end = 0;
5291   si->op = target->op;
5292   return sis;
5293 }
5294 
5295 static scan_info **
grn_scan_info_build_simple_operation(grn_ctx * ctx,grn_obj * expr,int * n,grn_operator logical_op,grn_bool record_exist)5296 grn_scan_info_build_simple_operation(grn_ctx *ctx,
5297                                      grn_obj *expr,
5298                                      int *n,
5299                                      grn_operator logical_op,
5300                                      grn_bool record_exist)
5301 {
5302   grn_expr *e = (grn_expr *)expr;
5303   grn_expr_code *target;
5304   grn_expr_code *constant;
5305   grn_expr_code *operator;
5306   scan_info **sis;
5307   scan_info *si;
5308 
5309   target   = e->codes + 0;
5310   constant = e->codes + 1;
5311   operator = e->codes + 2;
5312 
5313   if (target->op != GRN_OP_GET_VALUE) {
5314     return NULL;
5315   }
5316   if (target->nargs != 1) {
5317     return NULL;
5318   }
5319   if (!target->value) {
5320     return NULL;
5321   }
5322 
5323   if (constant->op != GRN_OP_PUSH) {
5324     return NULL;
5325   }
5326   if (constant->nargs != 1) {
5327     return NULL;
5328   }
5329   if (!constant->value) {
5330     return NULL;
5331   }
5332 
5333   if (operator->nargs != 2) {
5334     return NULL;
5335   }
5336   switch (operator->op) {
5337   case GRN_OP_MATCH :
5338   case GRN_OP_NEAR :
5339   case GRN_OP_SIMILAR :
5340   case GRN_OP_PREFIX :
5341   case GRN_OP_SUFFIX :
5342   case GRN_OP_EQUAL :
5343   case GRN_OP_NOT_EQUAL :
5344   case GRN_OP_LESS :
5345   case GRN_OP_GREATER :
5346   case GRN_OP_LESS_EQUAL :
5347   case GRN_OP_GREATER_EQUAL :
5348   case GRN_OP_TERM_EXTRACT :
5349   case GRN_OP_REGEXP :
5350     break;
5351   default :
5352     return NULL;
5353     break;
5354   }
5355 
5356   sis = grn_scan_info_build_simple_open(ctx, n, logical_op);
5357   if (!sis) {
5358     return NULL;
5359   }
5360 
5361   si = sis[0];
5362   si->end = 2;
5363   si->op = operator->op;
5364   si->args[si->nargs++] = target->value;
5365   si->args[si->nargs++] = constant->value;
5366   {
5367     int32_t weight = 0;
5368     if (operator->value && operator->value->header.domain == GRN_DB_INT32) {
5369       weight = GRN_INT32_VALUE(operator->value);
5370     }
5371     scan_info_build_match(ctx, si, weight);
5372   }
5373   return sis;
5374 }
5375 
5376 static scan_info **
grn_scan_info_build_simple_and_operations(grn_ctx * ctx,grn_obj * expr,int * n,grn_operator logical_op,grn_bool record_exist)5377 grn_scan_info_build_simple_and_operations(grn_ctx *ctx,
5378                                           grn_obj *expr,
5379                                           int *n,
5380                                           grn_operator logical_op,
5381                                           grn_bool record_exist)
5382 {
5383   grn_expr *e = (grn_expr *)expr;
5384   scan_info **sis = NULL;
5385   int n_sis = 0;
5386   int i;
5387   int nth_sis;
5388 
5389   for (i = 0, nth_sis = 0; i < e->codes_curr; i += 3, nth_sis++) {
5390     grn_expr_code *target = e->codes + i;
5391     grn_expr_code *constant = e->codes + i + 1;
5392     grn_expr_code *operator = e->codes + i + 2;
5393 
5394     if (target->op != GRN_OP_GET_VALUE) {
5395       return NULL;
5396     }
5397     if (target->nargs != 1) {
5398       return NULL;
5399     }
5400     if (!target->value) {
5401       return NULL;
5402     }
5403 
5404     if (constant->op != GRN_OP_PUSH) {
5405       return NULL;
5406     }
5407     if (constant->nargs != 1) {
5408       return NULL;
5409     }
5410     if (!constant->value) {
5411       return NULL;
5412     }
5413 
5414     if (operator->nargs != 2) {
5415       return NULL;
5416     }
5417     switch (operator->op) {
5418     case GRN_OP_MATCH :
5419     case GRN_OP_NEAR :
5420     case GRN_OP_SIMILAR :
5421     case GRN_OP_PREFIX :
5422     case GRN_OP_SUFFIX :
5423     case GRN_OP_EQUAL :
5424     case GRN_OP_NOT_EQUAL :
5425     case GRN_OP_LESS :
5426     case GRN_OP_GREATER :
5427     case GRN_OP_LESS_EQUAL :
5428     case GRN_OP_GREATER_EQUAL :
5429     case GRN_OP_TERM_EXTRACT :
5430     case GRN_OP_REGEXP :
5431       break;
5432     default :
5433       return NULL;
5434       break;
5435     }
5436 
5437     if (nth_sis > 0) {
5438       grn_expr_code *logical_operator = e->codes + i + 3;
5439 
5440       if (logical_operator->op != GRN_OP_AND) {
5441         return NULL;
5442       }
5443       if (logical_operator->nargs != 2) {
5444         return NULL;
5445       }
5446 
5447       i++;
5448     }
5449   }
5450   n_sis = nth_sis;
5451 
5452   sis = GRN_CALLOC(sizeof(scan_info *) * n_sis);
5453   if (!sis) {
5454     return NULL;
5455   }
5456 
5457   for (i = 0, nth_sis = 0; i < e->codes_curr; i += 3, nth_sis++) {
5458     grn_expr_code *target = e->codes + i;
5459     grn_expr_code *constant = e->codes + i + 1;
5460     grn_expr_code *operator = e->codes + i + 2;
5461     scan_info *si;
5462 
5463     sis[nth_sis] = si = grn_scan_info_open(ctx, i);
5464     if (!si) {
5465       goto exit;
5466     }
5467     si->args[si->nargs++] = target->value;
5468     si->args[si->nargs++] = constant->value;
5469     si->op = operator->op;
5470     si->end = i + 2;
5471     si->flags &= ~SCAN_PUSH;
5472     if (nth_sis == 0) {
5473       si->logical_op = logical_op;
5474     } else {
5475       si->logical_op = GRN_OP_AND;
5476     }
5477     {
5478       int32_t weight = 0;
5479       if (operator->value && operator->value->header.domain == GRN_DB_INT32) {
5480         weight = GRN_INT32_VALUE(operator->value);
5481       }
5482       scan_info_build_match(ctx, si, weight);
5483     }
5484 
5485     if (nth_sis > 0) {
5486       i++;
5487     }
5488   }
5489 
5490   *n = n_sis;
5491   return sis;
5492 
5493 exit :
5494   if (n_sis > 0) {
5495     for (i = 0; i < n_sis; i++) {
5496       scan_info *si = sis[i];
5497       if (si) {
5498         grn_scan_info_close(ctx, si);
5499       }
5500     }
5501     GRN_FREE(sis);
5502   }
5503 
5504   return NULL;
5505 }
5506 
5507 static scan_info **
grn_scan_info_build_simple(grn_ctx * ctx,grn_obj * expr,int * n,grn_operator logical_op,grn_bool record_exist)5508 grn_scan_info_build_simple(grn_ctx *ctx, grn_obj *expr, int *n,
5509                            grn_operator logical_op, grn_bool record_exist)
5510 {
5511   grn_expr *e = (grn_expr *)expr;
5512 
5513   if (e->codes_curr == 1) {
5514     return grn_scan_info_build_simple_value(ctx,
5515                                             expr,
5516                                             n,
5517                                             logical_op,
5518                                             record_exist);
5519   } else if (e->codes_curr == 3) {
5520     return grn_scan_info_build_simple_operation(ctx,
5521                                                 expr,
5522                                                 n,
5523                                                 logical_op,
5524                                                 record_exist);
5525   } else if (e->codes_curr % 4 == 3) {
5526     return grn_scan_info_build_simple_and_operations(ctx,
5527                                                      expr,
5528                                                      n,
5529                                                      logical_op,
5530                                                      record_exist);
5531   }
5532 
5533   return NULL;
5534 }
5535 
5536 scan_info **
grn_scan_info_build(grn_ctx * ctx,grn_obj * expr,int * n,grn_operator op,grn_bool record_exist)5537 grn_scan_info_build(grn_ctx *ctx, grn_obj *expr, int *n,
5538                     grn_operator op, grn_bool record_exist)
5539 {
5540   scan_info **sis;
5541 
5542   sis = grn_scan_info_build_simple(ctx, expr, n, op, record_exist);
5543 #ifdef GRN_WITH_MRUBY
5544   if (!sis) {
5545     grn_ctx_impl_mrb_ensure_init(ctx);
5546     if (ctx->rc != GRN_SUCCESS) {
5547       return NULL;
5548     }
5549     if (ctx->impl->mrb.state) {
5550       return grn_mrb_scan_info_build(ctx, expr, n, op, record_exist);
5551     }
5552   }
5553 #endif
5554   if (!sis) {
5555     sis = grn_scan_info_build_full(ctx, expr, n, op, record_exist);
5556   }
5557   return sis;
5558 }
5559 
5560 void
grn_inspect_scan_info_list(grn_ctx * ctx,grn_obj * buffer,scan_info ** sis,int n)5561 grn_inspect_scan_info_list(grn_ctx *ctx, grn_obj *buffer, scan_info **sis, int n)
5562 {
5563   int i;
5564 
5565   for (i = 0; i < n; i++) {
5566     scan_info *si = sis[i];
5567 
5568     grn_text_printf(ctx, buffer, "[%d]\n", i);
5569     grn_text_printf(ctx, buffer,
5570                     "  op:         <%s>\n",
5571                     grn_operator_to_string(si->op));
5572     grn_text_printf(ctx, buffer,
5573                     "  logical_op: <%s>\n",
5574                     grn_operator_to_string(si->logical_op));
5575 
5576     if (si->op == GRN_OP_CALL) {
5577       int i;
5578       for (i = 0; i < si->nargs; i++) {
5579         grn_text_printf(ctx, buffer, "  args[%d]:    <", i);
5580         grn_inspect(ctx, buffer, si->args[i]);
5581         GRN_TEXT_PUTS(ctx, buffer, ">\n");
5582       }
5583     } else {
5584       GRN_TEXT_PUTS(ctx, buffer, "  index:      <");
5585       grn_inspect(ctx, buffer, &(si->index));
5586       GRN_TEXT_PUTS(ctx, buffer, ">\n");
5587 
5588       GRN_TEXT_PUTS(ctx, buffer, "  query:      <");
5589       grn_inspect(ctx, buffer, si->query);
5590       GRN_TEXT_PUTS(ctx, buffer, ">\n");
5591     }
5592 
5593     grn_text_printf(ctx, buffer,
5594                     "  expr:       <%d..%d>\n", si->start, si->end);
5595   }
5596 }
5597 
5598 void
grn_p_scan_info_list(grn_ctx * ctx,scan_info ** sis,int n)5599 grn_p_scan_info_list(grn_ctx *ctx, scan_info **sis, int n)
5600 {
5601   grn_obj inspected;
5602   GRN_TEXT_INIT(&inspected, 0);
5603   grn_inspect_scan_info_list(ctx, &inspected, sis, n);
5604   printf("%.*s\n",
5605          (int)GRN_TEXT_LEN(&inspected),
5606          GRN_TEXT_VALUE(&inspected));
5607   GRN_OBJ_FIN(ctx, &inspected);
5608 }
5609 
5610 inline static int32_t
exec_result_to_score(grn_ctx * ctx,grn_obj * result,grn_obj * score_buffer)5611 exec_result_to_score(grn_ctx *ctx, grn_obj *result, grn_obj *score_buffer)
5612 {
5613   if (!result) {
5614     return 0;
5615   }
5616 
5617   switch (result->header.type) {
5618   case GRN_VOID :
5619     return 0;
5620   case GRN_BULK :
5621     switch (result->header.domain) {
5622     case GRN_DB_BOOL :
5623       return GRN_BOOL_VALUE(result) ? 1 : 0;
5624     case GRN_DB_INT32 :
5625       return GRN_INT32_VALUE(result);
5626     default :
5627       GRN_BULK_REWIND(score_buffer);
5628       if (grn_obj_cast(ctx, result, score_buffer, GRN_FALSE) != GRN_SUCCESS) {
5629         return 1;
5630       }
5631       return GRN_INT32_VALUE(score_buffer);
5632     }
5633   case GRN_UVECTOR :
5634   case GRN_PVECTOR :
5635   case GRN_VECTOR :
5636     return 1;
5637   default :
5638     return 1; /* TODO: 1 is reasonable? */
5639   }
5640 }
5641 
5642 static void
grn_table_select_sequential(grn_ctx * ctx,grn_obj * table,grn_obj * expr,grn_obj * v,grn_obj * res,grn_operator op)5643 grn_table_select_sequential(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
5644                             grn_obj *v, grn_obj *res, grn_operator op)
5645 {
5646   grn_obj *result;
5647   grn_obj score_buffer;
5648   int32_t score;
5649   grn_id id, *idp;
5650   grn_table_cursor *tc;
5651   grn_hash_cursor *hc;
5652   grn_hash *s = (grn_hash *)res;
5653   grn_expr_executor *executor;
5654 
5655   executor = grn_expr_executor_open(ctx, expr);
5656   if (!executor) {
5657     return;
5658   }
5659   GRN_INT32_INIT(&score_buffer, 0);
5660   switch (op) {
5661   case GRN_OP_OR :
5662     if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
5663       while ((id = grn_table_cursor_next(ctx, tc))) {
5664         result = grn_expr_executor_exec(ctx, executor, id);
5665         if (ctx->rc) {
5666           break;
5667         }
5668         score = exec_result_to_score(ctx, result, &score_buffer);
5669         if (score > 0) {
5670           grn_rset_recinfo *ri;
5671           if (grn_hash_add(ctx, s, &id, s->key_size, (void **)&ri, NULL)) {
5672             grn_table_add_subrec(res, ri, score, (grn_rset_posinfo *)&id, 1);
5673           }
5674         }
5675       }
5676       grn_table_cursor_close(ctx, tc);
5677     }
5678     break;
5679   case GRN_OP_AND :
5680     if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) {
5681       while (grn_hash_cursor_next(ctx, hc)) {
5682         grn_hash_cursor_get_key(ctx, hc, (void **) &idp);
5683         result = grn_expr_executor_exec(ctx, executor, *idp);
5684         if (ctx->rc) {
5685           break;
5686         }
5687         score = exec_result_to_score(ctx, result, &score_buffer);
5688         if (score > 0) {
5689           grn_rset_recinfo *ri;
5690           grn_hash_cursor_get_value(ctx, hc, (void **) &ri);
5691           grn_table_add_subrec(res, ri, score, (grn_rset_posinfo *)idp, 1);
5692         } else {
5693           grn_hash_cursor_delete(ctx, hc, NULL);
5694         }
5695       }
5696       grn_hash_cursor_close(ctx, hc);
5697     }
5698     break;
5699   case GRN_OP_AND_NOT :
5700     if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) {
5701       while (grn_hash_cursor_next(ctx, hc)) {
5702         grn_hash_cursor_get_key(ctx, hc, (void **) &idp);
5703         result = grn_expr_executor_exec(ctx, executor, *idp);
5704         if (ctx->rc) {
5705           break;
5706         }
5707         score = exec_result_to_score(ctx, result, &score_buffer);
5708         if (score > 0) {
5709           grn_hash_cursor_delete(ctx, hc, NULL);
5710         }
5711       }
5712       grn_hash_cursor_close(ctx, hc);
5713     }
5714     break;
5715   case GRN_OP_ADJUST :
5716     if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) {
5717       while (grn_hash_cursor_next(ctx, hc)) {
5718         grn_hash_cursor_get_key(ctx, hc, (void **) &idp);
5719         result = grn_expr_executor_exec(ctx, executor, *idp);
5720         if (ctx->rc) {
5721           break;
5722         }
5723         score = exec_result_to_score(ctx, result, &score_buffer);
5724         if (score > 0) {
5725           grn_rset_recinfo *ri;
5726           grn_hash_cursor_get_value(ctx, hc, (void **) &ri);
5727           grn_table_add_subrec(res, ri, score, (grn_rset_posinfo *)idp, 1);
5728         }
5729       }
5730       grn_hash_cursor_close(ctx, hc);
5731     }
5732     break;
5733   default :
5734     break;
5735   }
5736   GRN_OBJ_FIN(ctx, &score_buffer);
5737   grn_expr_executor_close(ctx, executor);
5738 }
5739 
5740 static inline void
grn_table_select_index_report(grn_ctx * ctx,const char * tag,grn_obj * index)5741 grn_table_select_index_report(grn_ctx *ctx, const char *tag, grn_obj *index)
5742 {
5743   grn_report_index(ctx, "[table][select]", tag, index);
5744 }
5745 
5746 static inline void
grn_table_select_index_not_used_report(grn_ctx * ctx,const char * tag,grn_obj * index,const char * reason)5747 grn_table_select_index_not_used_report(grn_ctx *ctx,
5748                                        const char *tag,
5749                                        grn_obj *index,
5750                                        const char *reason)
5751 {
5752   grn_report_index_not_used(ctx, "[table][select]", tag, index, reason);
5753 }
5754 
5755 static inline grn_bool
grn_table_select_index_use_sequential_search(grn_ctx * ctx,grn_obj * table,grn_obj * res,grn_operator logical_op,const char * tag,grn_obj * index)5756 grn_table_select_index_use_sequential_search(grn_ctx *ctx,
5757                                              grn_obj *table,
5758                                              grn_obj *res,
5759                                              grn_operator logical_op,
5760                                              const char *tag,
5761                                              grn_obj *index)
5762 {
5763   int n_records;
5764   int n_filtered_records;
5765   double filtered_ratio;
5766   grn_obj reason;
5767 
5768   if (logical_op != GRN_OP_AND) {
5769     return GRN_FALSE;
5770   }
5771 
5772   n_records = grn_table_size(ctx, table);
5773   n_filtered_records = grn_table_size(ctx, res);
5774   if (n_records == 0) {
5775     filtered_ratio = 1.0;
5776   } else {
5777     filtered_ratio = (double)n_filtered_records / (double)n_records;
5778   }
5779 
5780   if (filtered_ratio >= grn_table_select_enough_filtered_ratio) {
5781     return GRN_FALSE;
5782   }
5783 
5784   if (n_filtered_records > grn_table_select_max_n_enough_filtered_records) {
5785     return GRN_FALSE;
5786   }
5787 
5788   GRN_TEXT_INIT(&reason, 0);
5789   grn_text_printf(ctx, &reason,
5790                   "enough filtered: %.2f%%(%d/%d) < %.2f%% && %d <= %d",
5791                   filtered_ratio * 100,
5792                   n_filtered_records,
5793                   n_records,
5794                   grn_table_select_enough_filtered_ratio * 100,
5795                   n_filtered_records,
5796                   grn_table_select_max_n_enough_filtered_records);
5797   GRN_TEXT_PUTC(ctx, &reason, '\0');
5798   grn_table_select_index_not_used_report(ctx,
5799                                          tag,
5800                                          index,
5801                                          GRN_TEXT_VALUE(&reason));
5802   GRN_OBJ_FIN(ctx, &reason);
5803   return GRN_TRUE;
5804 }
5805 
5806 static inline grn_bool
grn_table_select_index_equal(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_obj * res)5807 grn_table_select_index_equal(grn_ctx *ctx,
5808                              grn_obj *table,
5809                              grn_obj *index,
5810                              scan_info *si,
5811                              grn_obj *res)
5812 {
5813   grn_bool processed = GRN_FALSE;
5814 
5815   if (GRN_BULK_VSIZE(si->query) == 0) {
5816     /* We can't use index for empty value. */
5817     return GRN_FALSE;
5818   }
5819 
5820   if (si->flags & SCAN_ACCESSOR) {
5821     if (index->header.type == GRN_ACCESSOR && !((grn_accessor *)index)->next) {
5822       grn_obj dest;
5823       grn_accessor *a = (grn_accessor *)index;
5824       grn_posting posting;
5825       posting.sid = 1;
5826       posting.pos = 0;
5827       posting.weight = 0;
5828       switch (a->action) {
5829       case GRN_ACCESSOR_GET_ID :
5830         grn_table_select_index_report(ctx, "[equal][accessor][id]", table);
5831         GRN_UINT32_INIT(&dest, 0);
5832         if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
5833           posting.rid = GRN_UINT32_VALUE(&dest);
5834           if (posting.rid) {
5835             if (posting.rid == grn_table_at(ctx, table, posting.rid)) {
5836               grn_ii_posting_add(ctx, &posting, (grn_hash *)res,
5837                                  si->logical_op);
5838             }
5839           }
5840           processed = GRN_TRUE;
5841         }
5842         grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
5843         GRN_OBJ_FIN(ctx, &dest);
5844         break;
5845       case GRN_ACCESSOR_GET_KEY :
5846         grn_table_select_index_report(ctx, "[equal][accessor][key]", table);
5847         GRN_OBJ_INIT(&dest, GRN_BULK, 0, table->header.domain);
5848         if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
5849           if ((posting.rid = grn_table_get(ctx, table,
5850                                            GRN_BULK_HEAD(&dest),
5851                                            GRN_BULK_VSIZE(&dest)))) {
5852             grn_ii_posting_add(ctx, &posting, (grn_hash *)res,
5853                                si->logical_op);
5854           }
5855           processed = GRN_TRUE;
5856         }
5857         grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
5858         GRN_OBJ_FIN(ctx, &dest);
5859         break;
5860       }
5861     }
5862   } else {
5863     const char *tag = "[equal]";
5864     grn_obj *domain = grn_ctx_at(ctx, index->header.domain);
5865 
5866     if (domain) {
5867       grn_bool optimizable = GRN_FALSE;
5868 
5869       if (domain->header.domain == GRN_DB_SHORT_TEXT) {
5870         grn_obj *normalizer = NULL;
5871         grn_table_get_info(ctx, domain, NULL, NULL, NULL, &normalizer, NULL);
5872         if (normalizer == grn_ctx_get(ctx, "NormalizerAuto", -1)) {
5873           optimizable = GRN_TRUE;
5874         }
5875       } else {
5876         optimizable = GRN_TRUE;
5877       }
5878       if (optimizable &&
5879           grn_table_select_index_use_sequential_search(ctx,
5880                                                        table,
5881                                                        res,
5882                                                        si->logical_op,
5883                                                        tag,
5884                                                        index)) {
5885         domain = NULL;
5886       }
5887     }
5888 
5889     if (domain) {
5890       grn_id tid;
5891 
5892       grn_table_select_index_report(ctx, tag, index);
5893 
5894       if (GRN_OBJ_GET_DOMAIN(si->query) == DB_OBJ(domain)->id) {
5895         tid = GRN_RECORD_VALUE(si->query);
5896       } else {
5897         tid = grn_table_get(ctx, domain,
5898                             GRN_BULK_HEAD(si->query),
5899                             GRN_BULK_VSIZE(si->query));
5900       }
5901       if (tid != GRN_ID_NIL) {
5902         uint32_t sid;
5903         int32_t weight;
5904         grn_ii *ii = (grn_ii *)index;
5905         grn_ii_cursor *ii_cursor;
5906 
5907         sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
5908         weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
5909         ii_cursor = grn_ii_cursor_open(ctx, ii, tid,
5910                                        GRN_ID_NIL, GRN_ID_MAX,
5911                                        ii->n_elements, 0);
5912         if (ii_cursor) {
5913           grn_posting *posting;
5914           while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
5915             grn_posting new_posting;
5916 
5917             if (!(sid == 0 || posting->sid == sid)) {
5918               continue;
5919             }
5920 
5921             if (si->position.specified) {
5922               while ((posting = grn_ii_cursor_next_pos(ctx, ii_cursor))) {
5923                 if (posting->pos == si->position.start) {
5924                   break;
5925                 }
5926               }
5927               if (!posting) {
5928                 continue;
5929               }
5930             }
5931 
5932             new_posting = *posting;
5933             new_posting.weight *= weight;
5934             grn_ii_posting_add(ctx, &new_posting, (grn_hash *)res,
5935                                si->logical_op);
5936           }
5937           grn_ii_cursor_close(ctx, ii_cursor);
5938         }
5939       }
5940       processed = GRN_TRUE;
5941     }
5942     if (processed) {
5943       grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
5944     }
5945   }
5946 
5947   return processed;
5948 }
5949 
5950 static inline grn_bool
grn_table_select_index_not_equal(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_obj * res)5951 grn_table_select_index_not_equal(grn_ctx *ctx,
5952                                  grn_obj *table,
5953                                  grn_obj *index,
5954                                  scan_info *si,
5955                                  grn_obj *res)
5956 {
5957   grn_bool processed = GRN_FALSE;
5958 
5959   if (GRN_BULK_VSIZE(si->query) == 0) {
5960     /* We can't use index for empty value. */
5961     return GRN_FALSE;
5962   }
5963 
5964   if (si->logical_op != GRN_OP_AND) {
5965     /* We can't use index for OR and AND_NOT. */
5966     return GRN_FALSE;
5967   }
5968 
5969   if (si->flags & SCAN_ACCESSOR) {
5970     if (index->header.type == GRN_ACCESSOR && !((grn_accessor *)index)->next) {
5971       grn_obj dest;
5972       grn_accessor *a = (grn_accessor *)index;
5973       grn_id id;
5974       switch (a->action) {
5975       case GRN_ACCESSOR_GET_ID :
5976         grn_table_select_index_report(ctx, "[not-equal][accessor][id]", table);
5977         GRN_UINT32_INIT(&dest, 0);
5978         if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
5979           id = GRN_UINT32_VALUE(&dest);
5980           if (id != GRN_ID_NIL) {
5981             if (id == grn_table_at(ctx, table, id)) {
5982               grn_hash_delete(ctx, (grn_hash *)res, &id, sizeof(grn_id), NULL);
5983             }
5984           }
5985           processed = GRN_TRUE;
5986         }
5987         GRN_OBJ_FIN(ctx, &dest);
5988         break;
5989       case GRN_ACCESSOR_GET_KEY :
5990         grn_table_select_index_report(ctx, "[not-equal][accessor][key]", table);
5991         GRN_OBJ_INIT(&dest, GRN_BULK, 0, table->header.domain);
5992         if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
5993           id = grn_table_get(ctx, table,
5994                              GRN_BULK_HEAD(&dest),
5995                              GRN_BULK_VSIZE(&dest));
5996           if (id != GRN_ID_NIL) {
5997             grn_hash_delete(ctx, (grn_hash *)res, &id, sizeof(grn_id), NULL);
5998           }
5999           processed = GRN_TRUE;
6000         }
6001         GRN_OBJ_FIN(ctx, &dest);
6002         break;
6003       }
6004     }
6005   } else {
6006     grn_obj *domain = grn_ctx_at(ctx, index->header.domain);
6007     if (domain) {
6008       grn_id tid;
6009       if (GRN_OBJ_GET_DOMAIN(si->query) == DB_OBJ(domain)->id) {
6010         tid = GRN_RECORD_VALUE(si->query);
6011       } else {
6012         tid = grn_table_get(ctx, domain,
6013                             GRN_BULK_HEAD(si->query),
6014                             GRN_BULK_VSIZE(si->query));
6015       }
6016       if (tid == GRN_ID_NIL) {
6017         processed = GRN_TRUE;
6018       } else {
6019         uint32_t sid;
6020         int32_t weight;
6021         grn_ii *ii = (grn_ii *)index;
6022         grn_ii_cursor *ii_cursor;
6023 
6024         grn_table_select_index_report(ctx, "[not-equal]", index);
6025 
6026         sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
6027         weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
6028         ii_cursor = grn_ii_cursor_open(ctx, ii, tid,
6029                                        GRN_ID_NIL, GRN_ID_MAX,
6030                                        ii->n_elements, 0);
6031         if (ii_cursor) {
6032           grn_posting *posting;
6033           while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
6034             if (!(sid == 0 || posting->sid == sid)) {
6035               continue;
6036             }
6037 
6038             if (si->position.specified) {
6039               while ((posting = grn_ii_cursor_next_pos(ctx, ii_cursor))) {
6040                 if (posting->pos == si->position.start) {
6041                   break;
6042                 }
6043               }
6044               if (!posting) {
6045                 continue;
6046               }
6047             }
6048 
6049             grn_hash_delete(ctx, (grn_hash *)res,
6050                             &(posting->rid), sizeof(grn_id),
6051                             NULL);
6052           }
6053           grn_ii_cursor_close(ctx, ii_cursor);
6054           processed = GRN_TRUE;
6055         }
6056       }
6057     }
6058   }
6059 
6060   return processed;
6061 }
6062 
6063 static grn_bool
grn_table_select_index_prefix(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_obj * res)6064 grn_table_select_index_prefix(grn_ctx *ctx,
6065                               grn_obj *table,
6066                               grn_obj *index,
6067                               scan_info *si,
6068                               grn_obj *res)
6069 {
6070   grn_bool processed = GRN_FALSE;
6071   if (si->flags & SCAN_ACCESSOR) {
6072     if (index->header.type == GRN_ACCESSOR &&
6073         !((grn_accessor *)index)->next) {
6074       grn_obj dest;
6075       grn_accessor *a = (grn_accessor *)index;
6076       grn_posting posting;
6077       posting.sid = 1;
6078       posting.pos = 0;
6079       posting.weight = 0;
6080       switch (a->action) {
6081       case GRN_ACCESSOR_GET_ID :
6082         /* todo */
6083         break;
6084       case GRN_ACCESSOR_GET_KEY :
6085         if (si->op == GRN_OP_SUFFIX) {
6086           grn_table_select_index_report(ctx,
6087                                         "[suffix][accessor][key]", table);
6088         } else {
6089           grn_table_select_index_report(ctx,
6090                                         "[prefix][accessor][key]", table);
6091         }
6092         GRN_OBJ_INIT(&dest, GRN_BULK, 0, table->header.domain);
6093         if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
6094           grn_hash *pres;
6095           if ((pres = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
6096                                       GRN_OBJ_TABLE_HASH_KEY))) {
6097             grn_id *key;
6098             grn_table_search(ctx, table,
6099                              GRN_BULK_HEAD(&dest), GRN_BULK_VSIZE(&dest),
6100                              si->op, (grn_obj *)pres, GRN_OP_OR);
6101             GRN_HASH_EACH(ctx, pres, id, &key, NULL, NULL, {
6102               posting.rid = *key;
6103               grn_ii_posting_add(ctx, &posting, (grn_hash *)res,
6104                                  si->logical_op);
6105             });
6106             grn_hash_close(ctx, pres);
6107           }
6108           processed = GRN_TRUE;
6109         }
6110         grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
6111         GRN_OBJ_FIN(ctx, &dest);
6112       }
6113     }
6114   } else {
6115     grn_obj **indexes = &GRN_PTR_VALUE(&si->index);
6116     int i, n_indexes = GRN_BULK_VSIZE(&si->index)/sizeof(grn_obj *);
6117     for (i = 0; i < n_indexes; i++) {
6118       grn_obj *index = indexes[i];
6119       grn_obj *lexicon = grn_ctx_at(ctx, index->header.domain);
6120       if (lexicon) {
6121         grn_hash *keys;
6122         if ((keys = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
6123                                     GRN_OBJ_TABLE_HASH_KEY))) {
6124           grn_id *key;
6125           if (si->op == GRN_OP_SUFFIX) {
6126             grn_table_select_index_report(ctx, "[suffix]", index);
6127           } else {
6128             grn_table_select_index_report(ctx, "[prefix]", index);
6129           }
6130           grn_table_search(ctx, lexicon,
6131                           GRN_BULK_HEAD(si->query),
6132                           GRN_BULK_VSIZE(si->query),
6133                           si->op, (grn_obj *)keys, GRN_OP_OR);
6134           grn_obj_unlink(ctx, lexicon);
6135           GRN_HASH_EACH(ctx, keys, id, &key, NULL, NULL, {
6136             grn_ii_at(ctx, (grn_ii *)index, *key, (grn_hash *)res, si->logical_op);
6137           });
6138           grn_hash_close(ctx, keys);
6139         }
6140         grn_obj_unlink(ctx, lexicon);
6141       }
6142     }
6143     grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
6144     processed = GRN_TRUE;
6145   }
6146   return processed;
6147 }
6148 
6149 static grn_bool
grn_table_select_index_suffix(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_obj * res)6150 grn_table_select_index_suffix(grn_ctx *ctx,
6151                               grn_obj *table,
6152                               grn_obj *index,
6153                               scan_info *si,
6154                               grn_obj *res)
6155 {
6156   grn_obj *domain;
6157   if (si->flags & SCAN_ACCESSOR) {
6158     domain = table;
6159   } else {
6160     domain = grn_ctx_at(ctx, index->header.domain);
6161   }
6162   if (domain->header.type != GRN_TABLE_PAT_KEY) {
6163     return GRN_FALSE;
6164   }
6165   if (!(domain->header.flags & GRN_OBJ_KEY_WITH_SIS)) {
6166     return GRN_FALSE;
6167   }
6168   return grn_table_select_index_prefix(ctx, table, index, si, res);
6169 }
6170 
6171 static inline grn_bool
grn_table_select_index_match(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_obj * res,grn_id * min_id)6172 grn_table_select_index_match(grn_ctx *ctx,
6173                              grn_obj *table,
6174                              grn_obj *index,
6175                              scan_info *si,
6176                              grn_obj *res,
6177                              grn_id *min_id)
6178 {
6179   grn_obj wv, **ip = &GRN_PTR_VALUE(&si->index);
6180   int j;
6181   int n_indexes = GRN_BULK_VSIZE(&si->index)/sizeof(grn_obj *);
6182   int32_t *wp = &GRN_INT32_VALUE(&si->wv);
6183   grn_search_optarg optarg;
6184   grn_bool minimum_min_id_is_set = GRN_FALSE;
6185   grn_id minimum_min_id = GRN_ID_NIL;
6186   unsigned int previous_n_hits = grn_table_size(ctx, res);
6187 
6188   GRN_INT32_INIT(&wv, GRN_OBJ_VECTOR);
6189   if (si->op == GRN_OP_MATCH) {
6190     optarg.mode = GRN_OP_EXACT;
6191   } else {
6192     optarg.mode = si->op;
6193   }
6194   optarg.max_interval = 0;
6195   optarg.similarity_threshold = 0;
6196   switch (si->op) {
6197   case GRN_OP_NEAR :
6198   case GRN_OP_NEAR2 :
6199     optarg.max_interval = si->max_interval;
6200     break;
6201   case GRN_OP_SIMILAR :
6202     optarg.similarity_threshold = si->similarity_threshold;
6203     break;
6204   default :
6205     break;
6206   }
6207   optarg.weight_vector = (int *)GRN_BULK_HEAD(&wv);
6208   /* optarg.vector_size = GRN_BULK_VSIZE(&si->wv); */
6209   optarg.vector_size = 1;
6210   optarg.proc = NULL;
6211   optarg.max_size = 0;
6212   optarg.match_info.flags |= GRN_MATCH_INFO_GET_MIN_RECORD_ID;
6213   ctx->flags |= GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
6214   for (j = 0; j < n_indexes; j++, ip++, wp += 2) {
6215     uint32_t sid = (uint32_t) wp[0];
6216     int32_t weight = wp[1];
6217     if (grn_table_select_and_min_skip_enable) {
6218       optarg.match_info.min = *min_id;
6219     } else {
6220       optarg.match_info.min = GRN_ID_NIL;
6221     }
6222     if (sid) {
6223       int weight_index = sid - 1;
6224       int current_vector_size;
6225       current_vector_size = GRN_BULK_VSIZE(&wv)/sizeof(int32_t);
6226       if (weight_index < current_vector_size) {
6227         ((int *)GRN_BULK_HEAD(&wv))[weight_index] = weight;
6228       } else {
6229         GRN_INT32_SET_AT(ctx, &wv, weight_index, weight);
6230       }
6231       optarg.weight_vector = &GRN_INT32_VALUE(&wv);
6232       optarg.vector_size = GRN_BULK_VSIZE(&wv)/sizeof(int32_t);
6233     } else {
6234       optarg.weight_vector = NULL;
6235       optarg.vector_size = weight;
6236     }
6237     optarg.scorer = GRN_PTR_VALUE_AT(&(si->scorers), j);
6238     optarg.scorer_args_expr =
6239       GRN_PTR_VALUE_AT(&(si->scorer_args_exprs), j);
6240     optarg.scorer_args_expr_offset =
6241       GRN_UINT32_VALUE_AT(&(si->scorer_args_expr_offsets), j);
6242     if (j < n_indexes - 1) {
6243       if (sid && ip[0] == ip[1]) { continue; }
6244     } else {
6245       ctx->flags &= ~GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
6246     }
6247     grn_obj_search(ctx, ip[0], si->query, res, si->logical_op, &optarg);
6248     if (optarg.weight_vector) {
6249       int i;
6250       for (i = 0; i < optarg.vector_size; i++) {
6251         optarg.weight_vector[i] = 0;
6252       }
6253     }
6254     GRN_BULK_REWIND(&wv);
6255     if (!minimum_min_id_is_set ||
6256         optarg.match_info.min < minimum_min_id) {
6257       minimum_min_id_is_set = GRN_TRUE;
6258       minimum_min_id = optarg.match_info.min;
6259     }
6260   }
6261   if ((si->logical_op == GRN_OP_AND) ||
6262       (si->logical_op == GRN_OP_OR && previous_n_hits == 0)) {
6263     *min_id = minimum_min_id;
6264   } else {
6265     *min_id = GRN_ID_NIL;
6266   }
6267   GRN_OBJ_FIN(ctx, &wv);
6268 
6269   return GRN_TRUE;
6270 }
6271 
6272 static inline grn_bool
grn_table_select_index_call_selector(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_obj * selector,grn_obj * res)6273 grn_table_select_index_call_selector(grn_ctx *ctx,
6274                                      grn_obj *table,
6275                                      grn_obj *index,
6276                                      scan_info *si,
6277                                      grn_obj *selector,
6278                                      grn_obj *res)
6279 {
6280   grn_bool processed = GRN_FALSE;
6281   grn_proc *proc = (grn_proc *)selector;
6282   grn_rc rc;
6283 
6284   if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
6285     char name[GRN_TABLE_MAX_KEY_SIZE];
6286     int name_size;
6287     char tag[GRN_TABLE_MAX_KEY_SIZE];
6288     name_size = grn_obj_name(ctx,
6289                              (grn_obj *)selector,
6290                              name,
6291                              GRN_TABLE_MAX_KEY_SIZE);
6292     grn_snprintf(tag, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
6293                  "[selector][%.*s]",
6294                  name_size, name);
6295     grn_table_select_index_report(ctx, tag, index);
6296   }
6297 
6298   if (index && index->header.type == GRN_ACCESSOR) {
6299     grn_operator selector_op;
6300     grn_obj *accessor = index;
6301     grn_accessor *a = (grn_accessor *)accessor;
6302 
6303     selector_op = grn_proc_get_selector_operator(ctx, selector);
6304     if (a->next) {
6305       unsigned int accessor_deep = 0;
6306       grn_obj *base_table = NULL;
6307       grn_obj *base_index = NULL;
6308       grn_obj *base_res = NULL;
6309 
6310       for (; a; a = a->next) {
6311         if (a->next) {
6312           accessor_deep++;
6313         } else {
6314           grn_index_datum index_data;
6315           unsigned int n_index_datum;
6316 
6317           if (grn_obj_is_table(ctx, a->obj)) {
6318             base_table = a->obj;
6319           } else {
6320             base_table = grn_ctx_at(ctx, a->obj->header.domain);
6321           }
6322           n_index_datum = grn_column_find_index_data(ctx,
6323                                                      a->obj,
6324                                                      selector_op,
6325                                                      &index_data,
6326                                                      1);
6327           if (n_index_datum > 0) {
6328             base_index = index_data.index;
6329           }
6330           base_res = grn_table_create(ctx, NULL, 0, NULL,
6331                                       GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
6332                                       base_table, NULL);
6333         }
6334       }
6335       rc = proc->callbacks.function.selector(ctx,
6336                                              base_table,
6337                                              base_index,
6338                                              si->nargs,
6339                                              si->args,
6340                                              base_res,
6341                                              GRN_OP_OR);
6342       if (rc == GRN_SUCCESS) {
6343         grn_accessor_resolve(ctx,
6344                              accessor,
6345                              accessor_deep,
6346                              base_res,
6347                              res,
6348                              si->logical_op);
6349       }
6350       grn_obj_close(ctx, base_res);
6351     } else {
6352       grn_index_datum index_data;
6353       unsigned int n_index_datum;
6354       grn_obj *target_index = NULL;
6355 
6356       n_index_datum = grn_column_find_index_data(ctx,
6357                                                  a->obj,
6358                                                  selector_op,
6359                                                  &index_data,
6360                                                  1);
6361       if (n_index_datum > 0) {
6362         target_index = index_data.index;
6363       }
6364       rc = proc->callbacks.function.selector(ctx,
6365                                              table,
6366                                              target_index,
6367                                              si->nargs,
6368                                              si->args,
6369                                              res,
6370                                              si->logical_op);
6371     }
6372   } else {
6373     rc = proc->callbacks.function.selector(ctx,
6374                                            table,
6375                                            index,
6376                                            si->nargs,
6377                                            si->args,
6378                                            res,
6379                                            si->logical_op);
6380   }
6381 
6382   if (rc) {
6383     /* TODO: report error */
6384   } else {
6385     processed = GRN_TRUE;
6386   }
6387 
6388   return processed;
6389 }
6390 
6391 static inline grn_bool
grn_table_select_index_range_key(grn_ctx * ctx,grn_obj * table,scan_info * si,grn_operator logical_op,grn_obj * res)6392 grn_table_select_index_range_key(grn_ctx *ctx,
6393                                  grn_obj *table,
6394                                  scan_info *si,
6395                                  grn_operator logical_op,
6396                                  grn_obj *res)
6397 {
6398   const char *tag = "[range][key]";
6399   grn_bool processed = GRN_FALSE;
6400   grn_obj key;
6401 
6402   if (grn_table_select_index_use_sequential_search(ctx,
6403                                                    table,
6404                                                    res,
6405                                                    logical_op,
6406                                                    tag,
6407                                                    table)) {
6408     return GRN_FALSE;
6409   }
6410 
6411   GRN_OBJ_INIT(&key, GRN_BULK, 0, table->header.domain);
6412   if (grn_obj_cast(ctx, si->query, &key, GRN_FALSE) == GRN_SUCCESS) {
6413     grn_table_cursor *cursor;
6414     const void *min = NULL, *max = NULL;
6415     unsigned int min_size = 0, max_size = 0;
6416     int offset = 0;
6417     int limit = -1;
6418     int flags = GRN_CURSOR_ASCENDING;
6419 
6420     grn_table_select_index_report(ctx, tag, table);
6421 
6422     switch (si->op) {
6423     case GRN_OP_LESS :
6424       flags |= GRN_CURSOR_LT;
6425       max = GRN_BULK_HEAD(&key);
6426       max_size = GRN_BULK_VSIZE(&key);
6427       break;
6428     case GRN_OP_GREATER :
6429       flags |= GRN_CURSOR_GT;
6430       min = GRN_BULK_HEAD(&key);
6431       min_size = GRN_BULK_VSIZE(&key);
6432       break;
6433     case GRN_OP_LESS_EQUAL :
6434       flags |= GRN_CURSOR_LE;
6435       max = GRN_BULK_HEAD(&key);
6436       max_size = GRN_BULK_VSIZE(&key);
6437       break;
6438     case GRN_OP_GREATER_EQUAL :
6439       flags |= GRN_CURSOR_GE;
6440       min = GRN_BULK_HEAD(&key);
6441       min_size = GRN_BULK_VSIZE(&key);
6442       break;
6443     default :
6444       break;
6445     }
6446     cursor = grn_table_cursor_open(ctx, table,
6447                                    min, min_size, max, max_size,
6448                                    offset, limit, flags);
6449     if (cursor) {
6450       uint32_t sid;
6451       int32_t weight;
6452 
6453       sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
6454       weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
6455 
6456       if (sid == 0) {
6457         grn_posting posting = {0};
6458 
6459         posting.weight = weight - 1;
6460         while ((posting.rid = grn_table_cursor_next(ctx, cursor))) {
6461           grn_ii_posting_add(ctx, &posting, (grn_hash *)res, logical_op);
6462         }
6463       }
6464       processed = GRN_TRUE;
6465       grn_table_cursor_close(ctx, cursor);
6466     }
6467 
6468     grn_ii_resolve_sel_and(ctx, (grn_hash *)res, logical_op);
6469   }
6470   GRN_OBJ_FIN(ctx, &key);
6471 
6472   return processed;
6473 }
6474 
6475 static inline grn_bool
grn_table_select_index_range_column(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_operator logical_op,grn_obj * res)6476 grn_table_select_index_range_column(grn_ctx *ctx, grn_obj *table,
6477                                     grn_obj *index,
6478                                     scan_info *si, grn_operator logical_op,
6479                                     grn_obj *res)
6480 {
6481   const char *tag = "[range]";
6482   grn_bool processed = GRN_FALSE;
6483   grn_obj *index_table;
6484   grn_obj range;
6485 
6486   index_table = grn_ctx_at(ctx, index->header.domain);
6487   if (!index_table) {
6488     return GRN_FALSE;
6489   }
6490 
6491   if (grn_table_select_index_use_sequential_search(ctx,
6492                                                    table,
6493                                                    res,
6494                                                    logical_op,
6495                                                    tag,
6496                                                    index_table)) {
6497     grn_obj_unlink(ctx, index_table);
6498     return GRN_FALSE;
6499   }
6500 
6501   GRN_OBJ_INIT(&range, GRN_BULK, 0, index_table->header.domain);
6502   if (grn_obj_cast(ctx, si->query, &range, GRN_FALSE) == GRN_SUCCESS) {
6503     grn_table_cursor *cursor;
6504     const void *min = NULL, *max = NULL;
6505     unsigned int min_size = 0, max_size = 0;
6506     int offset = 0;
6507     int limit = -1;
6508     int flags = GRN_CURSOR_ASCENDING;
6509 
6510     grn_table_select_index_report(ctx, "[range]", index);
6511 
6512     switch (si->op) {
6513     case GRN_OP_LESS :
6514       flags |= GRN_CURSOR_LT;
6515       max = GRN_BULK_HEAD(&range);
6516       max_size = GRN_BULK_VSIZE(&range);
6517       break;
6518     case GRN_OP_GREATER :
6519       flags |= GRN_CURSOR_GT;
6520       min = GRN_BULK_HEAD(&range);
6521       min_size = GRN_BULK_VSIZE(&range);
6522       break;
6523     case GRN_OP_LESS_EQUAL :
6524       flags |= GRN_CURSOR_LE;
6525       max = GRN_BULK_HEAD(&range);
6526       max_size = GRN_BULK_VSIZE(&range);
6527       break;
6528     case GRN_OP_GREATER_EQUAL :
6529       flags |= GRN_CURSOR_GE;
6530       min = GRN_BULK_HEAD(&range);
6531       min_size = GRN_BULK_VSIZE(&range);
6532       break;
6533     default :
6534       break;
6535     }
6536     cursor = grn_table_cursor_open(ctx, index_table,
6537                                    min, min_size, max, max_size,
6538                                    offset, limit, flags);
6539     if (cursor) {
6540       grn_id tid;
6541       uint32_t sid;
6542       int32_t weight;
6543       grn_ii *ii = (grn_ii *)index;
6544 
6545       sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
6546       weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
6547       while ((tid = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
6548         grn_ii_cursor *ii_cursor;
6549 
6550         ii_cursor = grn_ii_cursor_open(ctx, ii, tid,
6551                                        GRN_ID_NIL, GRN_ID_MAX,
6552                                        ii->n_elements, 0);
6553         if (ii_cursor) {
6554           grn_posting *posting;
6555           while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
6556             grn_posting new_posting;
6557 
6558             if (!(sid == 0 || posting->sid == sid)) {
6559               continue;
6560             }
6561 
6562             if (si->position.specified) {
6563               while ((posting = grn_ii_cursor_next_pos(ctx, ii_cursor))) {
6564                 if (posting->pos == si->position.start) {
6565                   break;
6566                 }
6567               }
6568               if (!posting) {
6569                 continue;
6570               }
6571             }
6572 
6573             new_posting = *posting;
6574             new_posting.weight *= weight;
6575             grn_ii_posting_add(ctx, &new_posting, (grn_hash *)res, logical_op);
6576           }
6577         }
6578         grn_ii_cursor_close(ctx, ii_cursor);
6579       }
6580       processed = GRN_TRUE;
6581       grn_table_cursor_close(ctx, cursor);
6582     }
6583 
6584     grn_ii_resolve_sel_and(ctx, (grn_hash *)res, logical_op);
6585   }
6586   GRN_OBJ_FIN(ctx, &range);
6587 
6588   grn_obj_unlink(ctx, index_table);
6589 
6590   return processed;
6591 }
6592 
6593 static inline grn_bool
grn_table_select_index_range_accessor(grn_ctx * ctx,grn_obj * table,grn_obj * accessor,scan_info * si,grn_operator op,grn_obj * res)6594 grn_table_select_index_range_accessor(grn_ctx *ctx,
6595                                       grn_obj *table,
6596                                       grn_obj *accessor,
6597                                       scan_info *si,
6598                                       grn_operator op,
6599                                       grn_obj *res)
6600 {
6601   grn_rc rc;
6602   grn_accessor *a;
6603   grn_obj *last_obj = NULL;
6604   int n_accessors;
6605   grn_bool have_resolver = GRN_FALSE;
6606   grn_obj *base_res = NULL;
6607 
6608   for (a = (grn_accessor *)accessor; a; a = a->next) {
6609     if (!a->next) {
6610       last_obj = a->obj;
6611     }
6612   }
6613   n_accessors = 0;
6614   for (a = (grn_accessor *)accessor; a; a = a->next) {
6615     n_accessors++;
6616     if (GRN_OBJ_INDEX_COLUMNP(a->obj) ||
6617         grn_obj_is_table(ctx, a->obj)) {
6618       have_resolver = GRN_TRUE;
6619       break;
6620     }
6621   }
6622 
6623   {
6624     grn_obj *index;
6625     grn_obj *range;
6626 
6627     if (grn_obj_is_table(ctx, last_obj)) {
6628       index = last_obj;
6629       range = last_obj;
6630       base_res = grn_table_create(ctx, NULL, 0, NULL,
6631                                   GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
6632                                   range,
6633                                   NULL);
6634       if (!base_res) {
6635         return GRN_FALSE;
6636       }
6637       if (!grn_table_select_index_range_key(ctx, last_obj, si, GRN_OP_OR,
6638                                             base_res)) {
6639         grn_obj_unlink(ctx, base_res);
6640         return GRN_FALSE;
6641       }
6642     } else {
6643       if (grn_column_index(ctx, last_obj, si->op, &index, 1, NULL) == 0) {
6644         return GRN_FALSE;
6645       }
6646 
6647       range = grn_ctx_at(ctx, DB_OBJ(index)->range);
6648       base_res = grn_table_create(ctx, NULL, 0, NULL,
6649                                   GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
6650                                   range,
6651                                   NULL);
6652       if (!base_res) {
6653         return GRN_FALSE;
6654       }
6655       if (!grn_table_select_index_range_column(ctx, table, index, si, GRN_OP_OR,
6656                                                base_res)) {
6657         grn_obj_unlink(ctx, base_res);
6658         return GRN_FALSE;
6659       }
6660     }
6661     grn_table_select_index_report(ctx, "[range][accessor]", index);
6662   }
6663 
6664   if (n_accessors == 1 && have_resolver) {
6665     rc = grn_accessor_resolve(ctx, accessor, 1, base_res, res, op);
6666   } else {
6667     rc = grn_accessor_resolve(ctx, accessor, n_accessors - 1, base_res, res, op);
6668   }
6669   grn_obj_unlink(ctx, base_res);
6670 
6671   return rc == GRN_SUCCESS;
6672 }
6673 
6674 static inline grn_bool
grn_table_select_index_range(grn_ctx * ctx,grn_obj * table,grn_obj * index,scan_info * si,grn_obj * res)6675 grn_table_select_index_range(grn_ctx *ctx, grn_obj *table, grn_obj *index,
6676                              scan_info *si, grn_obj *res)
6677 {
6678   if (si->flags & SCAN_ACCESSOR) {
6679     switch (index->header.type) {
6680     case GRN_TABLE_PAT_KEY :
6681     case GRN_TABLE_DAT_KEY :
6682       /* table == index */
6683       return grn_table_select_index_range_key(ctx, table, si,
6684                                               si->logical_op, res);
6685     case GRN_ACCESSOR :
6686       return grn_table_select_index_range_accessor(ctx, table, index, si,
6687                                                    si->logical_op, res);
6688     default :
6689       return GRN_FALSE;
6690     }
6691   } else {
6692     return grn_table_select_index_range_column(ctx, table, index, si,
6693                                                si->logical_op, res);
6694   }
6695 }
6696 
6697 static inline grn_bool
grn_table_select_index(grn_ctx * ctx,grn_obj * table,scan_info * si,grn_obj * res,grn_id * min_id)6698 grn_table_select_index(grn_ctx *ctx, grn_obj *table, scan_info *si,
6699                        grn_obj *res, grn_id *min_id)
6700 {
6701   grn_bool processed = GRN_FALSE;
6702   if (!si->query) {
6703     if (si->op != GRN_OP_CALL || !grn_obj_is_selector_proc(ctx, si->args[0])) {
6704       return processed;
6705     }
6706   }
6707   if (GRN_BULK_VSIZE(&si->index)) {
6708     grn_obj *index = GRN_PTR_VALUE(&si->index);
6709     switch (si->op) {
6710     case GRN_OP_EQUAL :
6711       processed = grn_table_select_index_equal(ctx, table, index, si, res);
6712       break;
6713     case GRN_OP_NOT_EQUAL :
6714       processed = grn_table_select_index_not_equal(ctx, table, index, si, res);
6715       break;
6716     case GRN_OP_PREFIX :
6717       processed = grn_table_select_index_prefix(ctx, table, index, si, res);
6718       break;
6719     case GRN_OP_SUFFIX :
6720       processed = grn_table_select_index_suffix(ctx, table, index, si, res);
6721       break;
6722     case GRN_OP_MATCH :
6723     case GRN_OP_NEAR :
6724     case GRN_OP_NEAR2 :
6725     case GRN_OP_SIMILAR :
6726     case GRN_OP_REGEXP :
6727       processed = grn_table_select_index_match(ctx,
6728                                                table,
6729                                                index,
6730                                                si,
6731                                                res,
6732                                                min_id);
6733       break;
6734     case GRN_OP_TERM_EXTRACT :
6735       if (si->flags & SCAN_ACCESSOR) {
6736         if (index->header.type == GRN_ACCESSOR &&
6737             !((grn_accessor *)index)->next) {
6738           grn_accessor *a = (grn_accessor *)index;
6739           switch (a->action) {
6740           case GRN_ACCESSOR_GET_KEY :
6741             grn_table_select_index_report(ctx, "[term-extract][accessor][key]",
6742                                           table);
6743             grn_table_search(ctx, table,
6744                              GRN_TEXT_VALUE(si->query), GRN_TEXT_LEN(si->query),
6745                              GRN_OP_TERM_EXTRACT, res, si->logical_op);
6746             processed = GRN_TRUE;
6747             break;
6748           }
6749         }
6750       }
6751       break;
6752     case GRN_OP_CALL :
6753       if (grn_obj_is_selector_proc(ctx, si->args[0])) {
6754         processed = grn_table_select_index_call_selector(ctx,
6755                                                          table,
6756                                                          index,
6757                                                          si,
6758                                                          si->args[0],
6759                                                          res);
6760       }
6761       break;
6762     case GRN_OP_LESS :
6763     case GRN_OP_GREATER :
6764     case GRN_OP_LESS_EQUAL :
6765     case GRN_OP_GREATER_EQUAL :
6766       processed = grn_table_select_index_range(ctx, table, index, si, res);
6767       break;
6768     default :
6769       /* todo : implement */
6770       /* todo : handle SCAN_PRE_CONST */
6771       break;
6772     }
6773   } else {
6774     switch (si->op) {
6775     case GRN_OP_CALL :
6776       if (grn_obj_is_selector_proc(ctx, si->args[0])) {
6777         grn_rc rc;
6778         grn_proc *proc = (grn_proc *)(si->args[0]);
6779         if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
6780           char proc_name[GRN_TABLE_MAX_KEY_SIZE];
6781           int proc_name_size;
6782           char tag[GRN_TABLE_MAX_KEY_SIZE];
6783           proc_name_size = grn_obj_name(ctx, (grn_obj *)proc,
6784                                         proc_name, GRN_TABLE_MAX_KEY_SIZE);
6785           proc_name[proc_name_size] = '\0';
6786           grn_snprintf(tag, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
6787                        "[selector][no-index][%s]", proc_name);
6788           grn_table_select_index_report(ctx, tag, table);
6789         }
6790         rc = proc->callbacks.function.selector(ctx,
6791                                                table,
6792                                                NULL,
6793                                                si->nargs,
6794                                                si->args,
6795                                                res,
6796                                                si->logical_op);
6797         if (rc) {
6798           if (rc == GRN_FUNCTION_NOT_IMPLEMENTED) {
6799             ERRCLR(ctx);
6800           } else {
6801             /* TODO: report error */
6802           }
6803         } else {
6804           processed = GRN_TRUE;
6805         }
6806       }
6807     default :
6808       break;
6809     }
6810   }
6811   return processed;
6812 }
6813 
6814 grn_obj *
grn_table_select(grn_ctx * ctx,grn_obj * table,grn_obj * expr,grn_obj * res,grn_operator op)6815 grn_table_select(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
6816                  grn_obj *res, grn_operator op)
6817 {
6818   grn_obj *v;
6819   unsigned int res_size;
6820   grn_bool res_created = GRN_FALSE;
6821   if (res) {
6822     if (res->header.type != GRN_TABLE_HASH_KEY ||
6823         (res->header.domain != DB_OBJ(table)->id)) {
6824       ERR(GRN_INVALID_ARGUMENT, "hash table required");
6825       return NULL;
6826     }
6827   } else {
6828     if (!(res = grn_table_create(ctx, NULL, 0, NULL,
6829                                  GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, table, NULL))) {
6830       return NULL;
6831     }
6832     res_created = GRN_TRUE;
6833   }
6834   if (!(v = grn_expr_get_var_by_offset(ctx, expr, 0))) {
6835     ERR(GRN_INVALID_ARGUMENT, "at least one variable must be defined");
6836     return NULL;
6837   }
6838   GRN_API_ENTER;
6839   res_size = GRN_HASH_SIZE((grn_hash *)res);
6840   if (op == GRN_OP_OR || res_size) {
6841     int i;
6842     grn_scanner *scanner;
6843     scanner = grn_scanner_open(ctx, expr, op, res_size > 0);
6844     if (scanner) {
6845       grn_obj res_stack;
6846       grn_expr *e = (grn_expr *)scanner->expr;
6847       grn_expr_code *codes = e->codes;
6848       uint32_t codes_curr = e->codes_curr;
6849       grn_id min_id = GRN_ID_NIL;
6850       v = grn_expr_get_var_by_offset(ctx, (grn_obj *)e, 0);
6851       GRN_PTR_INIT(&res_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
6852       for (i = 0; i < scanner->n_sis; i++) {
6853         scan_info *si = scanner->sis[i];
6854         if (si->flags & SCAN_POP) {
6855           grn_obj *res_;
6856           GRN_PTR_POP(&res_stack, res_);
6857           grn_table_setoperation(ctx, res_, res, res_, si->logical_op);
6858           grn_obj_close(ctx, res);
6859           res = res_;
6860           min_id = GRN_ID_NIL;
6861         } else {
6862           grn_bool processed = GRN_FALSE;
6863           if (si->flags & SCAN_PUSH) {
6864             grn_obj *res_ = NULL;
6865             res_ = grn_table_create(ctx, NULL, 0, NULL,
6866                                     GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, table, NULL);
6867             if (!res_) {
6868               break;
6869             }
6870             GRN_PTR_PUT(ctx, &res_stack, res);
6871             res = res_;
6872             min_id = GRN_ID_NIL;
6873           }
6874           if (si->logical_op != GRN_OP_AND) {
6875             min_id = GRN_ID_NIL;
6876           }
6877           processed = grn_table_select_index(ctx, table, si, res, &min_id);
6878           if (!processed) {
6879             if (ctx->rc) { break; }
6880             e->codes = codes + si->start;
6881             e->codes_curr = si->end - si->start + 1;
6882             grn_table_select_sequential(ctx, table, (grn_obj *)e, v,
6883                                         res, si->logical_op);
6884             min_id = GRN_ID_NIL;
6885           }
6886         }
6887         GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
6888                       ":", "filter(%d)", grn_table_size(ctx, res));
6889         if (ctx->rc) {
6890           if (res_created) {
6891             grn_obj_close(ctx, res);
6892           }
6893           res = NULL;
6894           break;
6895         }
6896       }
6897 
6898       i = 0;
6899       if (!res_created) { i++; }
6900       for (; i < GRN_BULK_VSIZE(&res_stack) / sizeof(grn_obj *); i++) {
6901         grn_obj *stacked_res;
6902         stacked_res = *((grn_obj **)GRN_BULK_HEAD(&res_stack) + i);
6903         grn_obj_close(ctx, stacked_res);
6904       }
6905       GRN_OBJ_FIN(ctx, &res_stack);
6906       e->codes = codes;
6907       e->codes_curr = codes_curr;
6908 
6909       grn_scanner_close(ctx, scanner);
6910     } else {
6911       if (!ctx->rc) {
6912         grn_table_select_sequential(ctx, table, expr, v, res, op);
6913         if (ctx->rc) {
6914           if (res_created) {
6915             grn_obj_close(ctx, res);
6916           }
6917           res = NULL;
6918         }
6919       }
6920     }
6921   }
6922   GRN_API_RETURN(res);
6923 }
6924 
6925 /* grn_expr_parse */
6926 
6927 grn_obj *
grn_ptr_value_at(grn_obj * obj,int offset)6928 grn_ptr_value_at(grn_obj *obj, int offset)
6929 {
6930   int size = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
6931   if (offset < 0) { offset = size + offset; }
6932   return (0 <= offset && offset < size)
6933     ? (((grn_obj **)GRN_BULK_HEAD(obj))[offset])
6934     : NULL;
6935 }
6936 
6937 int32_t
grn_int32_value_at(grn_obj * obj,int offset)6938 grn_int32_value_at(grn_obj *obj, int offset)
6939 {
6940   int size = GRN_BULK_VSIZE(obj) / sizeof(int32_t);
6941   if (offset < 0) { offset = size + offset; }
6942   return (0 <= offset && offset < size)
6943     ? (((int32_t *)GRN_BULK_HEAD(obj))[offset])
6944     : 0;
6945 }
6946 
6947 /* grn_expr_create_from_str */
6948 
6949 #include "grn_snip.h"
6950 
6951 typedef struct {
6952   grn_ctx *ctx;
6953   grn_obj *e;
6954   grn_obj *v;
6955   const char *str;
6956   const char *cur;
6957   const char *str_end;
6958   grn_obj *table;
6959   grn_obj *default_column;
6960   grn_obj buf;
6961   grn_obj token_stack;
6962   grn_obj column_stack;
6963   grn_obj op_stack;
6964   grn_obj mode_stack;
6965   grn_obj max_interval_stack;
6966   grn_obj similarity_threshold_stack;
6967   grn_obj weight_stack;
6968   grn_operator default_op;
6969   grn_select_optarg opt;
6970   grn_operator default_mode;
6971   grn_expr_flags flags;
6972   grn_expr_flags default_flags;
6973   int escalation_threshold;
6974   int escalation_decaystep;
6975   int weight_offset;
6976   grn_hash *weight_set;
6977   snip_cond *snip_conds;
6978   grn_hash *object_literal;
6979   int paren_depth;
6980   struct {
6981     const char *string;
6982     size_t string_length;
6983     int token;
6984     int weight;
6985   } pending_token;
6986 } efs_info;
6987 
6988 typedef struct {
6989   grn_operator op;
6990   int weight;
6991 } efs_op;
6992 
6993 inline static void
skip_space(grn_ctx * ctx,efs_info * q)6994 skip_space(grn_ctx *ctx, efs_info *q)
6995 {
6996   unsigned int len;
6997   while (q->cur < q->str_end && grn_isspace(q->cur, ctx->encoding)) {
6998     /* null check and length check */
6999     if (!(len = grn_charlen(ctx, q->cur, q->str_end))) {
7000       q->cur = q->str_end;
7001       break;
7002     }
7003     q->cur += len;
7004   }
7005 }
7006 
7007 static grn_bool
parse_query_op(efs_info * q,efs_op * op,grn_operator * mode,int * option)7008 parse_query_op(efs_info *q, efs_op *op, grn_operator *mode, int *option)
7009 {
7010   grn_bool found = GRN_TRUE;
7011   const char *start, *end = q->cur;
7012   switch (*end) {
7013   case 'S' :
7014     *mode = GRN_OP_SIMILAR;
7015     start = ++end;
7016     *option = grn_atoi(start, q->str_end, (const char **)&end);
7017     if (start == end) { *option = DEFAULT_SIMILARITY_THRESHOLD; }
7018     q->cur = end;
7019     break;
7020   case 'N' :
7021     *mode = GRN_OP_NEAR;
7022     start = ++end;
7023     *option = grn_atoi(start, q->str_end, (const char **)&end);
7024     if (start == end) { *option = DEFAULT_MAX_INTERVAL; }
7025     q->cur = end;
7026     break;
7027   case 'n' :
7028     *mode = GRN_OP_NEAR2;
7029     start = ++end;
7030     *option = grn_atoi(start, q->str_end, (const char **)&end);
7031     if (start == end) { *option = DEFAULT_MAX_INTERVAL; }
7032     q->cur = end;
7033     break;
7034   case 'T' :
7035     *mode = GRN_OP_TERM_EXTRACT;
7036     start = ++end;
7037     *option = grn_atoi(start, q->str_end, (const char **)&end);
7038     if (start == end) { *option = DEFAULT_TERM_EXTRACT_POLICY; }
7039     q->cur = end;
7040     break;
7041   case 'X' : /* force exact mode */
7042     op->op = GRN_OP_AND;
7043     *mode = GRN_OP_EXACT;
7044     *option = 0;
7045     start = ++end;
7046     q->cur = end;
7047     break;
7048   default :
7049     found = GRN_FALSE;
7050     break;
7051   }
7052   return found;
7053 }
7054 
7055 #define DISABLE_UNUSED_CODE 1
7056 #ifndef DISABLE_UNUSED_CODE
7057 static const char *
get_weight_vector(grn_ctx * ctx,efs_info * query,const char * source)7058 get_weight_vector(grn_ctx *ctx, efs_info *query, const char *source)
7059 {
7060   const char *p;
7061 
7062   if (!query->opt.weight_vector &&
7063       !query->weight_set &&
7064       !(query->opt.weight_vector = GRN_CALLOC(sizeof(int) * DEFAULT_WEIGHT_VECTOR_SIZE))) {
7065     GRN_LOG(ctx, GRN_LOG_ALERT, "get_weight_vector malloc fail");
7066     return source;
7067   }
7068   for (p = source; p < query->str_end; ) {
7069     unsigned int key;
7070     int value;
7071 
7072     /* key, key is not zero */
7073     key = grn_atoui(p, query->str_end, &p);
7074     if (!key || key > GRN_ID_MAX) { break; }
7075 
7076     /* value */
7077     if (*p == ':') {
7078       p++;
7079       value = grn_atoi(p, query->str_end, &p);
7080     } else {
7081       value = 1;
7082     }
7083 
7084     if (query->weight_set) {
7085       int *pval;
7086       if (grn_hash_add(ctx, query->weight_set, &key, sizeof(unsigned int), (void **)&pval, NULL)) {
7087         *pval = value;
7088       }
7089     } else if (key < DEFAULT_WEIGHT_VECTOR_SIZE) {
7090       query->opt.weight_vector[key - 1] = value;
7091     } else {
7092       GRN_FREE(query->opt.weight_vector);
7093       query->opt.weight_vector = NULL;
7094       if (!(query->weight_set = grn_hash_create(ctx, NULL, sizeof(unsigned int), sizeof(int),
7095                                                 0))) {
7096         return source;
7097       }
7098       p = source;           /* reparse */
7099       continue;
7100     }
7101     if (*p != ',') { break; }
7102     p++;
7103   }
7104   return p;
7105 }
7106 
7107 static void
get_pragma(grn_ctx * ctx,efs_info * q)7108 get_pragma(grn_ctx *ctx, efs_info *q)
7109 {
7110   const char *start, *end = q->cur;
7111   while (end < q->str_end && *end == GRN_QUERY_PREFIX) {
7112     if (++end >= q->str_end) { break; }
7113     switch (*end) {
7114     case 'E' :
7115       start = ++end;
7116       q->escalation_threshold = grn_atoi(start, q->str_end, (const char **)&end);
7117       while (end < q->str_end && (('0' <= *end && *end <= '9') || *end == '-')) { end++; }
7118       if (*end == ',') {
7119         start = ++end;
7120         q->escalation_decaystep = grn_atoi(start, q->str_end, (const char **)&end);
7121       }
7122       q->cur = end;
7123       break;
7124     case 'D' :
7125       start = ++end;
7126       while (end < q->str_end && *end != GRN_QUERY_PREFIX && !grn_isspace(end, ctx->encoding)) {
7127         end++;
7128       }
7129       if (end > start) {
7130         switch (*start) {
7131         case 'O' :
7132           q->default_op = GRN_OP_OR;
7133           break;
7134         case GRN_QUERY_AND :
7135           q->default_op = GRN_OP_AND;
7136           break;
7137         case GRN_QUERY_AND_NOT :
7138           q->default_op = GRN_OP_AND_NOT;
7139           break;
7140         case GRN_QUERY_ADJ_INC :
7141           q->default_op = GRN_OP_ADJUST;
7142           break;
7143         }
7144       }
7145       q->cur = end;
7146       break;
7147     case 'W' :
7148       start = ++end;
7149       end = (char *)get_weight_vector(ctx, q, start);
7150       q->cur = end;
7151       break;
7152     }
7153   }
7154 }
7155 
7156 static int
section_weight_cb(grn_ctx * ctx,grn_hash * r,const void * rid,int sid,void * arg)7157 section_weight_cb(grn_ctx *ctx, grn_hash *r, const void *rid, int sid, void *arg)
7158 {
7159   int *w;
7160   grn_hash *s = (grn_hash *)arg;
7161   if (s && grn_hash_get(ctx, s, &sid, sizeof(grn_id), (void **)&w)) {
7162     return *w;
7163   } else {
7164     return 0;
7165   }
7166 }
7167 #endif
7168 
7169 #include "grn_ecmascript.h"
7170 #include "grn_ecmascript.c"
7171 
7172 static grn_rc
grn_expr_parser_open(grn_ctx * ctx)7173 grn_expr_parser_open(grn_ctx *ctx)
7174 {
7175   if (!ctx->impl->parser) {
7176     ctx->impl->parser = grn_expr_parserAlloc(malloc);
7177   }
7178   return ctx->rc;
7179 }
7180 
7181 #define PARSE(token) grn_expr_parser(ctx->impl->parser, (token), 0, q)
7182 
7183 static void
parse_query_accept_string(grn_ctx * ctx,efs_info * efsi,const char * str,unsigned int str_size)7184 parse_query_accept_string(grn_ctx *ctx, efs_info *efsi,
7185                           const char *str, unsigned int str_size)
7186 {
7187   grn_obj *column, *token;
7188   grn_operator mode;
7189   int32_t weight;
7190 
7191   GRN_PTR_PUT(ctx, &efsi->token_stack,
7192               grn_expr_add_str(ctx, efsi->e, str, str_size));
7193   {
7194     efs_info *q = efsi;
7195     PARSE(GRN_EXPR_TOKEN_QSTRING);
7196   }
7197 
7198   GRN_PTR_POP(&efsi->token_stack, token);
7199   column = grn_ptr_value_at(&efsi->column_stack, -1);
7200   grn_expr_append_const(efsi->ctx, efsi->e, column, GRN_OP_GET_VALUE, 1);
7201   grn_expr_append_obj(efsi->ctx, efsi->e, token, GRN_OP_PUSH, 1);
7202 
7203   mode = grn_int32_value_at(&efsi->mode_stack, -1);
7204   weight = grn_int32_value_at(&efsi->weight_stack, -1);
7205   switch (mode) {
7206   case GRN_OP_ASSIGN :
7207     grn_expr_append_op(efsi->ctx, efsi->e, mode, 2);
7208     break;
7209   case GRN_OP_NEAR :
7210   case GRN_OP_NEAR2 :
7211     {
7212       int max_interval;
7213       max_interval = grn_int32_value_at(&efsi->max_interval_stack, -1);
7214       grn_expr_append_const_int(efsi->ctx, efsi->e, max_interval,
7215                                 GRN_OP_PUSH, 1);
7216       if (weight == 0) {
7217         grn_expr_append_op(efsi->ctx, efsi->e, mode, 3);
7218       } else {
7219         grn_expr_append_const_int(efsi->ctx, efsi->e, weight, mode, 3);
7220       }
7221     }
7222     break;
7223   case GRN_OP_SIMILAR :
7224     {
7225       int similarity_threshold;
7226       similarity_threshold =
7227         grn_int32_value_at(&efsi->similarity_threshold_stack, -1);
7228       grn_expr_append_const_int(efsi->ctx, efsi->e, similarity_threshold,
7229                                 GRN_OP_PUSH, 1);
7230       if (weight == 0) {
7231         grn_expr_append_op(efsi->ctx, efsi->e, mode, 3);
7232       } else {
7233         grn_expr_append_const_int(efsi->ctx, efsi->e, weight, mode, 3);
7234       }
7235     }
7236     break;
7237   default :
7238     if (weight == 0) {
7239       grn_expr_append_op(efsi->ctx, efsi->e, mode, 2);
7240     } else {
7241       grn_expr_append_const_int(efsi->ctx, efsi->e, weight, mode, 2);
7242     }
7243     break;
7244   }
7245 }
7246 
7247 static void
parse_query_flush_pending_token(grn_ctx * ctx,efs_info * q)7248 parse_query_flush_pending_token(grn_ctx *ctx, efs_info *q)
7249 {
7250   const char *cur_keep;
7251 
7252   if (!(q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
7253     return;
7254   }
7255 
7256   if (q->pending_token.string_length == 0) {
7257     return;
7258   }
7259 
7260   cur_keep = q->cur;
7261   q->cur = q->pending_token.string;
7262   if (q->pending_token.token == GRN_EXPR_TOKEN_ADJUST ||
7263       q->pending_token.token == GRN_EXPR_TOKEN_NEGATIVE) {
7264     GRN_INT32_PUT(ctx, &q->weight_stack, q->pending_token.weight);
7265   }
7266   PARSE(q->pending_token.token);
7267   q->cur = cur_keep;
7268 
7269   q->pending_token.string = NULL;
7270   q->pending_token.string_length = 0;
7271   q->pending_token.token = 0;
7272   q->pending_token.weight = 0;
7273 }
7274 
7275 static void
parse_query_accept_logical_op(grn_ctx * ctx,efs_info * q,const char * string,unsigned int string_length,int token)7276 parse_query_accept_logical_op(grn_ctx *ctx,
7277                               efs_info *q,
7278                               const char *string,
7279                               unsigned int string_length,
7280                               int token)
7281 {
7282   if (!(q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
7283     PARSE(token);
7284     return;
7285   }
7286 
7287   if (q->pending_token.string_length > 0) {
7288     parse_query_accept_string(ctx,
7289                               q,
7290                               q->pending_token.string,
7291                               q->pending_token.string_length);
7292   }
7293 
7294   q->pending_token.string = string;
7295   q->pending_token.string_length = string_length;
7296   q->pending_token.token = token;
7297 }
7298 
7299 static void
parse_query_accept_adjust(grn_ctx * ctx,efs_info * q,const char * string,unsigned int string_length,int token,int weight)7300 parse_query_accept_adjust(grn_ctx *ctx,
7301                           efs_info *q,
7302                           const char *string,
7303                           unsigned int string_length,
7304                           int token,
7305                           int weight)
7306 {
7307   if (!(q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
7308     GRN_INT32_PUT(ctx, &q->weight_stack, weight);
7309     PARSE(token);
7310     return;
7311   }
7312 
7313   if (q->pending_token.string_length > 0) {
7314     parse_query_accept_string(ctx,
7315                               q,
7316                               q->pending_token.string,
7317                               q->pending_token.string_length);
7318   }
7319 
7320   q->pending_token.string = string;
7321   q->pending_token.string_length = string_length;
7322   q->pending_token.token = token;
7323   q->pending_token.weight = weight;
7324 }
7325 
7326 static grn_rc
parse_query_word(grn_ctx * ctx,efs_info * q)7327 parse_query_word(grn_ctx *ctx, efs_info *q)
7328 {
7329   const char *end;
7330   unsigned int len;
7331   GRN_BULK_REWIND(&q->buf);
7332   for (end = q->cur;; ) {
7333     /* null check and length check */
7334     if (!(len = grn_charlen(ctx, end, q->str_end))) {
7335       q->cur = q->str_end;
7336       break;
7337     }
7338     if (grn_isspace(end, ctx->encoding) ||
7339         *end == GRN_QUERY_PARENL || *end == GRN_QUERY_PARENR) {
7340       q->cur = end;
7341       break;
7342     }
7343     if (q->flags & GRN_EXPR_ALLOW_COLUMN && *end == GRN_QUERY_COLUMN) {
7344       grn_operator mode;
7345       grn_obj *c = grn_obj_column(ctx, q->table,
7346                                   GRN_TEXT_VALUE(&q->buf),
7347                                   GRN_TEXT_LEN(&q->buf));
7348       if (c && end + 1 < q->str_end) {
7349         switch (end[1]) {
7350         case '!' :
7351           mode = GRN_OP_NOT_EQUAL;
7352           q->cur = end + 2;
7353           break;
7354         case '=' :
7355           if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
7356             mode = GRN_OP_ASSIGN;
7357             q->cur = end + 2;
7358           } else {
7359             mode = GRN_OP_EQUAL;
7360             q->cur = end + 1;
7361           }
7362           break;
7363         case '<' :
7364           if (end + 2 < q->str_end && end[2] == '=') {
7365             mode = GRN_OP_LESS_EQUAL;
7366             q->cur = end + 3;
7367           } else {
7368             mode = GRN_OP_LESS;
7369             q->cur = end + 2;
7370           }
7371           break;
7372         case '>' :
7373           if (end + 2 < q->str_end && end[2] == '=') {
7374             mode = GRN_OP_GREATER_EQUAL;
7375             q->cur = end + 3;
7376           } else {
7377             mode = GRN_OP_GREATER;
7378             q->cur = end + 2;
7379           }
7380           break;
7381         case '@' :
7382           mode = GRN_OP_MATCH;
7383           q->cur = end + 2;
7384           break;
7385         case '^' :
7386           mode = GRN_OP_PREFIX;
7387           q->cur = end + 2;
7388           break;
7389         case '$' :
7390           mode = GRN_OP_SUFFIX;
7391           q->cur = end + 2;
7392           break;
7393         case '~' :
7394           mode = GRN_OP_REGEXP;
7395           q->cur = end + 2;
7396           break;
7397         default :
7398           mode = GRN_OP_EQUAL;
7399           q->cur = end + 1;
7400           break;
7401         }
7402       } else if (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
7403         GRN_TEXT_PUT(ctx, &q->buf, end, len);
7404         end += len;
7405         continue;
7406       } else {
7407         ERR(GRN_INVALID_ARGUMENT, "column lookup failed");
7408         q->cur = q->str_end;
7409         return ctx->rc;
7410       }
7411       parse_query_flush_pending_token(ctx, q);
7412       PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
7413       PARSE(GRN_EXPR_TOKEN_RELATIVE_OP);
7414 
7415       grn_expr_take_obj(ctx, q->e, c);
7416       GRN_PTR_PUT(ctx, &q->column_stack, c);
7417       GRN_INT32_PUT(ctx, &q->mode_stack, mode);
7418 
7419       return GRN_SUCCESS;
7420     } else if (GRN_TEXT_LEN(&q->buf) > 0 && *end == GRN_QUERY_PREFIX) {
7421       q->cur = end + 1;
7422       GRN_INT32_PUT(ctx, &q->mode_stack, GRN_OP_PREFIX);
7423       break;
7424     } else if (*end == GRN_QUERY_ESCAPE) {
7425       end += len;
7426       if (!(len = grn_charlen(ctx, end, q->str_end))) {
7427         q->cur = q->str_end;
7428         break;
7429       }
7430     }
7431     GRN_TEXT_PUT(ctx, &q->buf, end, len);
7432     end += len;
7433   }
7434   parse_query_flush_pending_token(ctx, q);
7435   parse_query_accept_string(ctx,
7436                             q,
7437                             GRN_TEXT_VALUE(&q->buf),
7438                             GRN_TEXT_LEN(&q->buf));
7439 
7440   return GRN_SUCCESS;
7441 }
7442 
7443 static grn_rc
parse_query(grn_ctx * ctx,efs_info * q)7444 parse_query(grn_ctx *ctx, efs_info *q)
7445 {
7446   int option = 0;
7447   grn_operator mode;
7448   efs_op op_, *op = &op_;
7449   grn_bool first_token = GRN_TRUE;
7450   grn_bool only_first_and = GRN_FALSE;
7451   grn_bool block_started = GRN_FALSE;
7452 
7453   op->op = q->default_op;
7454   op->weight = DEFAULT_WEIGHT;
7455   while (!ctx->rc) {
7456     skip_space(ctx, q);
7457 
7458     if (q->cur >= q->str_end) { goto exit; }
7459     if (*q->cur == '\0') { goto exit; }
7460 
7461     only_first_and = GRN_FALSE;
7462     switch (*q->cur) {
7463     case GRN_QUERY_PARENR :
7464       if (q->paren_depth == 0 && q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
7465         const char parenr = GRN_QUERY_PARENR;
7466         parse_query_flush_pending_token(ctx, q);
7467         parse_query_accept_string(ctx, q, &parenr, 1);
7468       } else {
7469         parse_query_flush_pending_token(ctx, q);
7470         PARSE(GRN_EXPR_TOKEN_PARENR);
7471         q->paren_depth--;
7472       }
7473       q->cur++;
7474       break;
7475     case GRN_QUERY_QUOTEL :
7476       q->cur++;
7477 
7478       {
7479         grn_bool closed = GRN_FALSE;
7480         const char *start, *s;
7481         start = s = q->cur;
7482         GRN_BULK_REWIND(&q->buf);
7483         while (1) {
7484           unsigned int len;
7485           if (s >= q->str_end) {
7486             q->cur = s;
7487             break;
7488           }
7489           len = grn_charlen(ctx, s, q->str_end);
7490           if (len == 0) {
7491             /* invalid string containing malformed multibyte char */
7492             goto exit;
7493           } else if (len == 1) {
7494             if (*s == GRN_QUERY_QUOTER) {
7495               q->cur = s + 1;
7496               closed = GRN_TRUE;
7497               break;
7498             } else if (*s == GRN_QUERY_ESCAPE && s + 1 < q->str_end) {
7499               s++;
7500               len = grn_charlen(ctx, s, q->str_end);
7501             }
7502           }
7503           GRN_TEXT_PUT(ctx, &q->buf, s, len);
7504           s += len;
7505         }
7506         if (!closed && (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
7507           q->cur = start - 1;
7508           parse_query_word(ctx, q);
7509         } else {
7510           parse_query_flush_pending_token(ctx, q);
7511           parse_query_accept_string(ctx,
7512                                     q,
7513                                     GRN_TEXT_VALUE(&q->buf),
7514                                     GRN_TEXT_LEN(&q->buf));
7515         }
7516       }
7517 
7518       break;
7519     case GRN_QUERY_PREFIX :
7520       q->cur++;
7521       if (parse_query_op(q, op, &mode, &option)) {
7522         switch (mode) {
7523         case GRN_OP_NEAR :
7524         case GRN_OP_NEAR2 :
7525           GRN_INT32_PUT(ctx, &q->max_interval_stack, option);
7526           break;
7527         case GRN_OP_SIMILAR :
7528           GRN_INT32_PUT(ctx, &q->similarity_threshold_stack, option);
7529           break;
7530         default :
7531           break;
7532         }
7533         GRN_INT32_PUT(ctx, &q->mode_stack, mode);
7534         parse_query_flush_pending_token(ctx, q);
7535         PARSE(GRN_EXPR_TOKEN_RELATIVE_OP);
7536       } else {
7537         q->cur--;
7538         parse_query_word(ctx, q);
7539       }
7540       break;
7541     case GRN_QUERY_AND :
7542       if (first_token) {
7543         only_first_and = GRN_TRUE;
7544       } else {
7545         op->op = GRN_OP_AND;
7546         parse_query_accept_logical_op(ctx,
7547                                       q,
7548                                       q->cur, 1,
7549                                       GRN_EXPR_TOKEN_LOGICAL_AND);
7550       }
7551       q->cur++;
7552       break;
7553     case GRN_QUERY_AND_NOT :
7554       if (first_token) {
7555         if (q->flags & GRN_EXPR_ALLOW_LEADING_NOT) {
7556           grn_obj *all_records = grn_ctx_get(ctx, "all_records", 11);
7557           if (all_records) {
7558             /* dummy token */
7559             PARSE(GRN_EXPR_TOKEN_QSTRING);
7560             grn_expr_append_obj(ctx, q->e, all_records, GRN_OP_PUSH, 1);
7561             grn_expr_append_op(ctx, q->e, GRN_OP_CALL, 0);
7562           }
7563         } else if (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
7564           parse_query_flush_pending_token(ctx, q);
7565           parse_query_accept_string(ctx, q, q->cur, 1);
7566           q->cur++;
7567           break;
7568         }
7569       }
7570       op->op = GRN_OP_AND_NOT;
7571       parse_query_accept_logical_op(ctx,
7572                                     q,
7573                                     q->cur, 1,
7574                                     GRN_EXPR_TOKEN_LOGICAL_AND_NOT);
7575       q->cur++;
7576       break;
7577     case GRN_QUERY_ADJ_INC :
7578       if (op->weight < 127) { op->weight++; }
7579       op->op = GRN_OP_ADJUST;
7580       parse_query_accept_adjust(ctx,
7581                                 q,
7582                                 q->cur, 1,
7583                                 GRN_EXPR_TOKEN_ADJUST,
7584                                 op->weight);
7585       q->cur++;
7586       break;
7587     case GRN_QUERY_ADJ_DEC :
7588       if (op->weight > -128) { op->weight--; }
7589       op->op = GRN_OP_ADJUST;
7590       parse_query_accept_adjust(ctx,
7591                                 q,
7592                                 q->cur, 1,
7593                                 GRN_EXPR_TOKEN_ADJUST,
7594                                 op->weight);
7595       q->cur++;
7596       break;
7597     case GRN_QUERY_ADJ_NEG :
7598       if (first_token) {
7599         parse_query_flush_pending_token(ctx, q);
7600         parse_query_accept_string(ctx, q, q->cur, 1);
7601       } else {
7602         op->op = GRN_OP_ADJUST;
7603         parse_query_accept_adjust(ctx,
7604                                   q,
7605                                   q->cur, 1,
7606                                   GRN_EXPR_TOKEN_NEGATIVE,
7607                                   -DEFAULT_WEIGHT);
7608       }
7609       q->cur++;
7610       break;
7611     case GRN_QUERY_PARENL :
7612       parse_query_flush_pending_token(ctx, q);
7613       PARSE(GRN_EXPR_TOKEN_PARENL);
7614       q->cur++;
7615       q->paren_depth++;
7616       block_started = GRN_TRUE;
7617       break;
7618     case 'O' :
7619       if (q->cur + 2 < q->str_end && q->cur[1] == 'R' && q->cur[2] == ' ') {
7620         if (first_token && (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
7621           parse_query_flush_pending_token(ctx, q);
7622           parse_query_accept_string(ctx, q, q->cur, 2);
7623         } else {
7624           parse_query_accept_logical_op(ctx,
7625                                         q,
7626                                         q->cur, 2,
7627                                         GRN_EXPR_TOKEN_LOGICAL_OR);
7628         }
7629         q->cur += 2;
7630         break;
7631       }
7632       /* fallthru */
7633     default :
7634       parse_query_word(ctx, q);
7635       break;
7636     }
7637     first_token = block_started;
7638     block_started = GRN_FALSE;
7639   }
7640 exit :
7641   if (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
7642     if (q->pending_token.string_length > 0) {
7643       parse_query_accept_string(ctx,
7644                                 q,
7645                                 q->pending_token.string,
7646                                 q->pending_token.string_length);
7647     } else if (only_first_and) {
7648       const char query_and[] = {GRN_QUERY_AND};
7649       parse_query_accept_string(ctx,
7650                                 q,
7651                                 query_and,
7652                                 1);
7653     }
7654     if (q->paren_depth > 0) {
7655       int paren_depth = q->paren_depth;
7656       while (paren_depth > 0) {
7657         const char parenl = GRN_QUERY_PARENL;
7658         parse_query_accept_string(ctx, q, &parenl, 1);
7659         PARSE(GRN_EXPR_TOKEN_PARENR);
7660         paren_depth--;
7661       }
7662     }
7663   }
7664   PARSE(0);
7665   return GRN_SUCCESS;
7666 }
7667 
7668 static grn_rc
get_string(grn_ctx * ctx,efs_info * q,char quote)7669 get_string(grn_ctx *ctx, efs_info *q, char quote)
7670 {
7671   const char *s;
7672   unsigned int len;
7673   grn_rc rc = GRN_END_OF_DATA;
7674   GRN_BULK_REWIND(&q->buf);
7675   for (s = q->cur + 1; s < q->str_end; s += len) {
7676     if (!(len = grn_charlen(ctx, s, q->str_end))) { break; }
7677     if (len == 1) {
7678       if (*s == quote) {
7679         s++;
7680         rc = GRN_SUCCESS;
7681         break;
7682       }
7683       if (*s == GRN_QUERY_ESCAPE && s + 1 < q->str_end) {
7684         s++;
7685         if (!(len = grn_charlen(ctx, s, q->str_end))) { break; }
7686       }
7687     }
7688     GRN_TEXT_PUT(ctx, &q->buf, s, len);
7689   }
7690   q->cur = s;
7691   return rc;
7692 }
7693 
7694 static grn_obj *
resolve_top_level_name(grn_ctx * ctx,const char * name,unsigned int name_size)7695 resolve_top_level_name(grn_ctx *ctx, const char *name, unsigned int name_size)
7696 {
7697   unsigned int i;
7698   unsigned int first_delimiter_position = 0;
7699   unsigned int n_delimiters = 0;
7700   grn_obj *top_level_object;
7701   grn_obj *object;
7702 
7703   for (i = 0; i < name_size; i++) {
7704     if (name[i] != GRN_DB_DELIMITER) {
7705       continue;
7706     }
7707 
7708     if (n_delimiters == 0) {
7709       first_delimiter_position = i;
7710     }
7711     n_delimiters++;
7712   }
7713 
7714   if (n_delimiters < 2) {
7715     return grn_ctx_get(ctx, name, name_size);
7716   }
7717 
7718   top_level_object = grn_ctx_get(ctx, name, first_delimiter_position);
7719   if (!top_level_object) {
7720     return NULL;
7721   }
7722   object = grn_obj_column(ctx, top_level_object,
7723                           name + first_delimiter_position + 1,
7724                           name_size - first_delimiter_position - 1);
7725   grn_obj_unlink(ctx, top_level_object);
7726   return object;
7727 }
7728 
7729 static grn_rc
get_identifier(grn_ctx * ctx,efs_info * q,grn_obj * name_resolve_context)7730 get_identifier(grn_ctx *ctx, efs_info *q, grn_obj *name_resolve_context)
7731 {
7732   const char *s;
7733   unsigned int len;
7734   grn_rc rc = GRN_SUCCESS;
7735   for (s = q->cur; s < q->str_end; s += len) {
7736     if (!(len = grn_charlen(ctx, s, q->str_end))) {
7737       rc = GRN_END_OF_DATA;
7738       goto exit;
7739     }
7740     if (grn_isspace(s, ctx->encoding)) { goto done; }
7741     if (len == 1) {
7742       switch (*s) {
7743       case '\0' : case '(' : case ')' : case '{' : case '}' :
7744       case '[' : case ']' : case ',' : case ':' : case '@' :
7745       case '?' : case '"' : case '*' : case '+' : case '-' :
7746       case '|' : case '/' : case '%' : case '!' : case '^' :
7747       case '&' : case '>' : case '<' : case '=' : case '~' :
7748         /* case '.' : */
7749         goto done;
7750         break;
7751       }
7752     }
7753   }
7754 done :
7755   len = s - q->cur;
7756   switch (*q->cur) {
7757   case 'd' :
7758     if (len == 6 && !memcmp(q->cur, "delete", 6)) {
7759       PARSE(GRN_EXPR_TOKEN_DELETE);
7760       goto exit;
7761     }
7762     break;
7763   case 'f' :
7764     if (len == 5 && !memcmp(q->cur, "false", 5)) {
7765       grn_obj buf;
7766       PARSE(GRN_EXPR_TOKEN_BOOLEAN);
7767       GRN_BOOL_INIT(&buf, 0);
7768       GRN_BOOL_SET(ctx, &buf, 0);
7769       grn_expr_append_const(ctx, q->e, &buf, GRN_OP_PUSH, 1);
7770       GRN_OBJ_FIN(ctx, &buf);
7771       goto exit;
7772     }
7773     break;
7774   case 'i' :
7775     if (len == 2 && !memcmp(q->cur, "in", 2)) {
7776       PARSE(GRN_EXPR_TOKEN_IN);
7777       goto exit;
7778     }
7779     break;
7780   case 'n' :
7781     if (len == 4 && !memcmp(q->cur, "null", 4)) {
7782       grn_obj buf;
7783       PARSE(GRN_EXPR_TOKEN_NULL);
7784       GRN_VOID_INIT(&buf);
7785       grn_expr_append_const(ctx, q->e, &buf, GRN_OP_PUSH, 1);
7786       GRN_OBJ_FIN(ctx, &buf);
7787       goto exit;
7788     }
7789     break;
7790   case 't' :
7791     if (len == 4 && !memcmp(q->cur, "true", 4)) {
7792       grn_obj buf;
7793       PARSE(GRN_EXPR_TOKEN_BOOLEAN);
7794       GRN_BOOL_INIT(&buf, 0);
7795       GRN_BOOL_SET(ctx, &buf, 1);
7796       grn_expr_append_const(ctx, q->e, &buf, GRN_OP_PUSH, 1);
7797       GRN_OBJ_FIN(ctx, &buf);
7798       goto exit;
7799     }
7800     break;
7801   }
7802   {
7803     grn_obj *obj;
7804     const char *name = q->cur;
7805     unsigned int name_size = s - q->cur;
7806     if (name_resolve_context) {
7807       if ((obj = grn_obj_column(ctx, name_resolve_context, name, name_size))) {
7808         if (obj->header.type == GRN_ACCESSOR) {
7809           grn_expr_take_obj(ctx, q->e, obj);
7810         }
7811         PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
7812         grn_expr_append_obj(ctx, q->e, obj, GRN_OP_GET_VALUE, 2);
7813         goto exit;
7814       }
7815     }
7816     if ((obj = grn_expr_get_var(ctx, q->e, name, name_size))) {
7817       PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
7818       grn_expr_append_obj(ctx, q->e, obj, GRN_OP_PUSH, 1);
7819       goto exit;
7820     }
7821     if ((obj = grn_obj_column(ctx, q->table, name, name_size))) {
7822       if (obj->header.type == GRN_ACCESSOR) {
7823         grn_expr_take_obj(ctx, q->e, obj);
7824       }
7825       PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
7826       grn_expr_append_obj(ctx, q->e, obj, GRN_OP_GET_VALUE, 1);
7827       goto exit;
7828     }
7829     if ((obj = resolve_top_level_name(ctx, name, name_size))) {
7830       if (obj->header.type == GRN_ACCESSOR) {
7831         grn_expr_take_obj(ctx, q->e, obj);
7832       }
7833       PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
7834       grn_expr_append_obj(ctx, q->e, obj, GRN_OP_PUSH, 1);
7835       goto exit;
7836     }
7837     if (q->flags & GRN_EXPR_SYNTAX_OUTPUT_COLUMNS) {
7838       PARSE(GRN_EXPR_TOKEN_NONEXISTENT_COLUMN);
7839     } else {
7840       rc = GRN_SYNTAX_ERROR;
7841       ERR(rc,
7842           "[expr][parse] unknown identifier: <%.*s>",
7843           (int)name_size,
7844           name);
7845     }
7846   }
7847 exit :
7848   q->cur = s;
7849   return rc;
7850 }
7851 
7852 static void
set_tos_minor_to_curr(grn_ctx * ctx,efs_info * q)7853 set_tos_minor_to_curr(grn_ctx *ctx, efs_info *q)
7854 {
7855   yyParser *parser = ctx->impl->parser;
7856   yyStackEntry *yytos = parser->yytos;
7857   yytos->minor.yy0 = ((grn_expr *)(q->e))->codes_curr;
7858 }
7859 
7860 static grn_obj *
parse_script_extract_name_resolve_context(grn_ctx * ctx,efs_info * q)7861 parse_script_extract_name_resolve_context(grn_ctx *ctx, efs_info *q)
7862 {
7863   grn_expr *expr = (grn_expr *)(q->e);
7864   grn_expr_code *code_start;
7865   grn_expr_code *code_last;
7866 
7867   if (expr->codes_curr == 0) {
7868     return NULL;
7869   }
7870 
7871   code_start = expr->codes;
7872   code_last = code_start + (expr->codes_curr - 1);
7873   switch (code_last->op) {
7874   case GRN_OP_GET_MEMBER :
7875     {
7876       unsigned int n_used_codes_for_key;
7877       grn_expr_code *code_key;
7878       grn_expr_code *code_receiver;
7879 
7880       code_key = code_last - 1;
7881       if (code_key < code_start) {
7882         return NULL;
7883       }
7884 
7885       n_used_codes_for_key = grn_expr_code_n_used_codes(ctx,
7886                                                         code_start,
7887                                                         code_key);
7888       if (n_used_codes_for_key == 0) {
7889         return NULL;
7890       }
7891       code_receiver = code_key - n_used_codes_for_key;
7892       if (code_receiver < code_start) {
7893         return NULL;
7894       }
7895       return code_receiver->value;
7896     }
7897     break;
7898   default :
7899     /* TODO: Support other operators. */
7900     return NULL;
7901     break;
7902   }
7903 }
7904 
7905 static grn_rc
parse_script(grn_ctx * ctx,efs_info * q)7906 parse_script(grn_ctx *ctx, efs_info *q)
7907 {
7908   grn_rc rc = GRN_SUCCESS;
7909   grn_obj *name_resolve_context = NULL;
7910   for (;;) {
7911     grn_obj *current_name_resolve_context = name_resolve_context;
7912     name_resolve_context = NULL;
7913     skip_space(ctx, q);
7914     if (q->cur >= q->str_end) { rc = GRN_END_OF_DATA; goto exit; }
7915     switch (*q->cur) {
7916     case '\0' :
7917       rc = GRN_END_OF_DATA;
7918       goto exit;
7919       break;
7920     case '(' :
7921       PARSE(GRN_EXPR_TOKEN_PARENL);
7922       q->cur++;
7923       break;
7924     case ')' :
7925       PARSE(GRN_EXPR_TOKEN_PARENR);
7926       q->cur++;
7927       break;
7928     case '{' :
7929       PARSE(GRN_EXPR_TOKEN_BRACEL);
7930       q->cur++;
7931       break;
7932     case '}' :
7933       PARSE(GRN_EXPR_TOKEN_BRACER);
7934       q->cur++;
7935       break;
7936     case '[' :
7937       PARSE(GRN_EXPR_TOKEN_BRACKETL);
7938       q->cur++;
7939       break;
7940     case ']' :
7941       PARSE(GRN_EXPR_TOKEN_BRACKETR);
7942       q->cur++;
7943       break;
7944     case ',' :
7945       PARSE(GRN_EXPR_TOKEN_COMMA);
7946       q->cur++;
7947       break;
7948     case '.' :
7949       PARSE(GRN_EXPR_TOKEN_DOT);
7950       name_resolve_context = parse_script_extract_name_resolve_context(ctx, q);
7951       q->cur++;
7952       break;
7953     case ':' :
7954       PARSE(GRN_EXPR_TOKEN_COLON);
7955       q->cur++;
7956       set_tos_minor_to_curr(ctx, q);
7957       grn_expr_append_op(ctx, q->e, GRN_OP_JUMP, 0);
7958       break;
7959     case '@' :
7960       switch (q->cur[1]) {
7961       case '^' :
7962         PARSE(GRN_EXPR_TOKEN_PREFIX);
7963         q->cur += 2;
7964         break;
7965       case '$' :
7966         PARSE(GRN_EXPR_TOKEN_SUFFIX);
7967         q->cur += 2;
7968         break;
7969       case '~' :
7970         PARSE(GRN_EXPR_TOKEN_REGEXP);
7971         q->cur += 2;
7972         break;
7973       default :
7974         PARSE(GRN_EXPR_TOKEN_MATCH);
7975         q->cur++;
7976         break;
7977       }
7978       break;
7979     case '~' :
7980       PARSE(GRN_EXPR_TOKEN_BITWISE_NOT);
7981       q->cur++;
7982       break;
7983     case '?' :
7984       PARSE(GRN_EXPR_TOKEN_QUESTION);
7985       q->cur++;
7986       set_tos_minor_to_curr(ctx, q);
7987       grn_expr_append_op(ctx, q->e, GRN_OP_CJUMP, 0);
7988       break;
7989     case '"' :
7990       if ((rc = get_string(ctx, q, '"'))) { goto exit; }
7991       PARSE(GRN_EXPR_TOKEN_STRING);
7992       grn_expr_append_const(ctx, q->e, &q->buf, GRN_OP_PUSH, 1);
7993       break;
7994     case '\'' :
7995       if ((rc = get_string(ctx, q, '\''))) { goto exit; }
7996       PARSE(GRN_EXPR_TOKEN_STRING);
7997       grn_expr_append_const(ctx, q->e, &q->buf, GRN_OP_PUSH, 1);
7998       break;
7999     case '*' :
8000       switch (q->cur[1]) {
8001       case 'N' :
8002         {
8003           const char *next_start = q->cur + 2;
8004           const char *end;
8005           int max_interval;
8006           max_interval = grn_atoi(next_start, q->str_end, &end);
8007           if (end == next_start) {
8008             max_interval = DEFAULT_MAX_INTERVAL;
8009           } else {
8010             next_start = end;
8011           }
8012           GRN_INT32_PUT(ctx, &q->max_interval_stack, max_interval);
8013           PARSE(GRN_EXPR_TOKEN_NEAR);
8014           q->cur = next_start;
8015         }
8016         break;
8017       case 'S' :
8018         PARSE(GRN_EXPR_TOKEN_SIMILAR);
8019         q->cur += 2;
8020         break;
8021       case 'T' :
8022         PARSE(GRN_EXPR_TOKEN_TERM_EXTRACT);
8023         q->cur += 2;
8024         break;
8025       case '>' :
8026         PARSE(GRN_EXPR_TOKEN_ADJUST);
8027         q->cur += 2;
8028         break;
8029       case '<' :
8030         PARSE(GRN_EXPR_TOKEN_ADJUST);
8031         q->cur += 2;
8032         break;
8033       case '~' :
8034         PARSE(GRN_EXPR_TOKEN_ADJUST);
8035         q->cur += 2;
8036         break;
8037       case '=' :
8038         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8039           PARSE(GRN_EXPR_TOKEN_STAR_ASSIGN);
8040           q->cur += 2;
8041         } else {
8042           ERR(GRN_UPDATE_NOT_ALLOWED,
8043               "'*=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8044         }
8045         break;
8046       default :
8047         PARSE(GRN_EXPR_TOKEN_STAR);
8048         q->cur++;
8049         break;
8050       }
8051       break;
8052     case '+' :
8053       switch (q->cur[1]) {
8054       case '+' :
8055         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8056           PARSE(GRN_EXPR_TOKEN_INCR);
8057           q->cur += 2;
8058         } else {
8059           ERR(GRN_UPDATE_NOT_ALLOWED,
8060               "'++' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8061         }
8062         break;
8063       case '=' :
8064         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8065           PARSE(GRN_EXPR_TOKEN_PLUS_ASSIGN);
8066           q->cur += 2;
8067         } else {
8068           ERR(GRN_UPDATE_NOT_ALLOWED,
8069               "'+=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8070         }
8071         break;
8072       default :
8073         PARSE(GRN_EXPR_TOKEN_PLUS);
8074         q->cur++;
8075         break;
8076       }
8077       break;
8078     case '-' :
8079       switch (q->cur[1]) {
8080       case '-' :
8081         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8082           PARSE(GRN_EXPR_TOKEN_DECR);
8083           q->cur += 2;
8084         } else {
8085           ERR(GRN_UPDATE_NOT_ALLOWED,
8086               "'--' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8087         }
8088         break;
8089       case '=' :
8090         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8091           PARSE(GRN_EXPR_TOKEN_MINUS_ASSIGN);
8092           q->cur += 2;
8093         } else {
8094           ERR(GRN_UPDATE_NOT_ALLOWED,
8095               "'-=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8096         }
8097         break;
8098       default :
8099         PARSE(GRN_EXPR_TOKEN_MINUS);
8100         q->cur++;
8101         break;
8102       }
8103       break;
8104     case '|' :
8105       switch (q->cur[1]) {
8106       case '|' :
8107         PARSE(GRN_EXPR_TOKEN_LOGICAL_OR);
8108         q->cur += 2;
8109         break;
8110       case '=' :
8111         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8112           PARSE(GRN_EXPR_TOKEN_OR_ASSIGN);
8113           q->cur += 2;
8114         } else {
8115           ERR(GRN_UPDATE_NOT_ALLOWED,
8116               "'|=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8117         }
8118         break;
8119       default :
8120         PARSE(GRN_EXPR_TOKEN_BITWISE_OR);
8121         q->cur++;
8122         break;
8123       }
8124       break;
8125     case '/' :
8126       switch (q->cur[1]) {
8127       case '=' :
8128         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8129           PARSE(GRN_EXPR_TOKEN_SLASH_ASSIGN);
8130           q->cur += 2;
8131         } else {
8132           ERR(GRN_UPDATE_NOT_ALLOWED,
8133               "'/=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8134         }
8135         break;
8136       default :
8137         PARSE(GRN_EXPR_TOKEN_SLASH);
8138         q->cur++;
8139         break;
8140       }
8141       break;
8142     case '%' :
8143       switch (q->cur[1]) {
8144       case '=' :
8145         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8146           PARSE(GRN_EXPR_TOKEN_MOD_ASSIGN);
8147           q->cur += 2;
8148         } else {
8149           ERR(GRN_UPDATE_NOT_ALLOWED,
8150               "'%%=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8151         }
8152         break;
8153       default :
8154         PARSE(GRN_EXPR_TOKEN_MOD);
8155         q->cur++;
8156         break;
8157       }
8158       break;
8159     case '!' :
8160       switch (q->cur[1]) {
8161       case '=' :
8162         PARSE(GRN_EXPR_TOKEN_NOT_EQUAL);
8163         q->cur += 2;
8164         break;
8165       default :
8166         PARSE(GRN_EXPR_TOKEN_NOT);
8167         q->cur++;
8168         break;
8169       }
8170       break;
8171     case '^' :
8172       switch (q->cur[1]) {
8173       case '=' :
8174         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8175           q->cur += 2;
8176           PARSE(GRN_EXPR_TOKEN_XOR_ASSIGN);
8177         } else {
8178           ERR(GRN_UPDATE_NOT_ALLOWED,
8179               "'^=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8180         }
8181         break;
8182       default :
8183         PARSE(GRN_EXPR_TOKEN_BITWISE_XOR);
8184         q->cur++;
8185         break;
8186       }
8187       break;
8188     case '&' :
8189       switch (q->cur[1]) {
8190       case '&' :
8191         PARSE(GRN_EXPR_TOKEN_LOGICAL_AND);
8192         q->cur += 2;
8193         break;
8194       case '=' :
8195         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8196           PARSE(GRN_EXPR_TOKEN_AND_ASSIGN);
8197           q->cur += 2;
8198         } else {
8199           ERR(GRN_UPDATE_NOT_ALLOWED,
8200               "'&=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8201         }
8202         break;
8203       case '!' :
8204         PARSE(GRN_EXPR_TOKEN_LOGICAL_AND_NOT);
8205         q->cur += 2;
8206         break;
8207       default :
8208         PARSE(GRN_EXPR_TOKEN_BITWISE_AND);
8209         q->cur++;
8210         break;
8211       }
8212       break;
8213     case '>' :
8214       switch (q->cur[1]) {
8215       case '>' :
8216         switch (q->cur[2]) {
8217         case '>' :
8218           switch (q->cur[3]) {
8219           case '=' :
8220             if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8221               PARSE(GRN_EXPR_TOKEN_SHIFTRR_ASSIGN);
8222               q->cur += 4;
8223             } else {
8224               ERR(GRN_UPDATE_NOT_ALLOWED,
8225                   "'>>>=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8226             }
8227             break;
8228           default :
8229             PARSE(GRN_EXPR_TOKEN_SHIFTRR);
8230             q->cur += 3;
8231             break;
8232           }
8233           break;
8234         case '=' :
8235           if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8236             PARSE(GRN_EXPR_TOKEN_SHIFTR_ASSIGN);
8237             q->cur += 3;
8238           } else {
8239             ERR(GRN_UPDATE_NOT_ALLOWED,
8240                 "'>>=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8241           }
8242           break;
8243         default :
8244           PARSE(GRN_EXPR_TOKEN_SHIFTR);
8245           q->cur += 2;
8246           break;
8247         }
8248         break;
8249       case '=' :
8250         PARSE(GRN_EXPR_TOKEN_GREATER_EQUAL);
8251         q->cur += 2;
8252         break;
8253       default :
8254         PARSE(GRN_EXPR_TOKEN_GREATER);
8255         q->cur++;
8256         break;
8257       }
8258       break;
8259     case '<' :
8260       switch (q->cur[1]) {
8261       case '<' :
8262         switch (q->cur[2]) {
8263         case '=' :
8264           if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8265             PARSE(GRN_EXPR_TOKEN_SHIFTL_ASSIGN);
8266             q->cur += 3;
8267           } else {
8268             ERR(GRN_UPDATE_NOT_ALLOWED,
8269                 "'<<=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8270           }
8271           break;
8272         default :
8273           PARSE(GRN_EXPR_TOKEN_SHIFTL);
8274           q->cur += 2;
8275           break;
8276         }
8277         break;
8278       case '=' :
8279         PARSE(GRN_EXPR_TOKEN_LESS_EQUAL);
8280         q->cur += 2;
8281         break;
8282       default :
8283         PARSE(GRN_EXPR_TOKEN_LESS);
8284         q->cur++;
8285         break;
8286       }
8287       break;
8288     case '=' :
8289       switch (q->cur[1]) {
8290       case '=' :
8291         PARSE(GRN_EXPR_TOKEN_EQUAL);
8292         q->cur += 2;
8293         break;
8294       default :
8295         if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
8296           PARSE(GRN_EXPR_TOKEN_ASSIGN);
8297           q->cur++;
8298         } else {
8299           ERR(GRN_UPDATE_NOT_ALLOWED,
8300               "'=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
8301         }
8302         break;
8303       }
8304       break;
8305     case '0' : case '1' : case '2' : case '3' : case '4' :
8306     case '5' : case '6' : case '7' : case '8' : case '9' :
8307       {
8308         const char *rest;
8309         int64_t int64 = grn_atoll(q->cur, q->str_end, &rest);
8310         // checks to see grn_atoll was appropriate
8311         // (NOTE: *q->cur begins with a digit. Thus, grn_atoll parses at least
8312         //        one char.)
8313         if (q->str_end != rest &&
8314             (*rest == '.' || *rest == 'e' || *rest == 'E' ||
8315              (*rest >= '0' && *rest <= '9'))) {
8316           char *rest_float;
8317           double d = strtod(q->cur, &rest_float);
8318           grn_obj floatbuf;
8319           GRN_FLOAT_INIT(&floatbuf, 0);
8320           GRN_FLOAT_SET(ctx, &floatbuf, d);
8321           grn_expr_append_const(ctx, q->e, &floatbuf, GRN_OP_PUSH, 1);
8322           rest = rest_float;
8323         } else {
8324           const char *rest64 = rest;
8325           grn_atoui(q->cur, q->str_end, &rest);
8326           // checks to see grn_atoi failed (see above NOTE)
8327           if ((int64 > UINT32_MAX) ||
8328               (q->str_end != rest && *rest >= '0' && *rest <= '9')) {
8329             grn_obj int64buf;
8330             GRN_INT64_INIT(&int64buf, 0);
8331             GRN_INT64_SET(ctx, &int64buf, int64);
8332             grn_expr_append_const(ctx, q->e, &int64buf, GRN_OP_PUSH, 1);
8333             rest = rest64;
8334           } else if (int64 > INT32_MAX || int64 < INT32_MIN) {
8335             grn_obj int64buf;
8336             GRN_INT64_INIT(&int64buf, 0);
8337             GRN_INT64_SET(ctx, &int64buf, int64);
8338             grn_expr_append_const(ctx, q->e, &int64buf, GRN_OP_PUSH, 1);
8339           } else {
8340             grn_obj int32buf;
8341             GRN_INT32_INIT(&int32buf, 0);
8342             GRN_INT32_SET(ctx, &int32buf, (int32_t)int64);
8343             grn_expr_append_const(ctx, q->e, &int32buf, GRN_OP_PUSH, 1);
8344           }
8345         }
8346         PARSE(GRN_EXPR_TOKEN_DECIMAL);
8347         q->cur = rest;
8348       }
8349       break;
8350     default :
8351       if ((rc = get_identifier(ctx, q, current_name_resolve_context))) {
8352         goto exit;
8353       }
8354       break;
8355     }
8356     if (ctx->rc) { rc = ctx->rc; break; }
8357   }
8358 exit :
8359   PARSE(0);
8360   return rc;
8361 }
8362 
8363 grn_rc
grn_expr_parse(grn_ctx * ctx,grn_obj * expr,const char * str,unsigned int str_size,grn_obj * default_column,grn_operator default_mode,grn_operator default_op,grn_expr_flags flags)8364 grn_expr_parse(grn_ctx *ctx, grn_obj *expr,
8365                const char *str, unsigned int str_size,
8366                grn_obj *default_column, grn_operator default_mode,
8367                grn_operator default_op, grn_expr_flags flags)
8368 {
8369   efs_info efsi;
8370   if (grn_expr_parser_open(ctx)) { return ctx->rc; }
8371   GRN_API_ENTER;
8372   efsi.ctx = ctx;
8373   efsi.str = str;
8374   if ((efsi.v = grn_expr_get_var_by_offset(ctx, expr, 0)) &&
8375       (efsi.table = grn_ctx_at(ctx, efsi.v->header.domain))) {
8376     GRN_TEXT_INIT(&efsi.buf, 0);
8377     GRN_INT32_INIT(&efsi.op_stack, GRN_OBJ_VECTOR);
8378     GRN_INT32_INIT(&efsi.mode_stack, GRN_OBJ_VECTOR);
8379     GRN_INT32_INIT(&efsi.max_interval_stack, GRN_OBJ_VECTOR);
8380     GRN_INT32_INIT(&efsi.similarity_threshold_stack, GRN_OBJ_VECTOR);
8381     GRN_INT32_INIT(&efsi.weight_stack, GRN_OBJ_VECTOR);
8382     GRN_PTR_INIT(&efsi.column_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
8383     GRN_PTR_INIT(&efsi.token_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
8384     efsi.e = expr;
8385     efsi.str = str;
8386     efsi.cur = str;
8387     efsi.str_end = str + str_size;
8388     efsi.default_column = default_column;
8389     GRN_PTR_PUT(ctx, &efsi.column_stack, default_column);
8390     GRN_INT32_PUT(ctx, &efsi.op_stack, default_op);
8391     GRN_INT32_PUT(ctx, &efsi.mode_stack, default_mode);
8392     GRN_INT32_PUT(ctx, &efsi.weight_stack, 0);
8393     efsi.default_flags = efsi.flags = flags;
8394     efsi.escalation_threshold = GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD;
8395     efsi.escalation_decaystep = DEFAULT_DECAYSTEP;
8396     efsi.weight_offset = 0;
8397     memset(&(efsi.opt), 0, sizeof(grn_select_optarg));
8398     efsi.opt.weight_vector = NULL;
8399     efsi.weight_set = NULL;
8400     efsi.object_literal = NULL;
8401     efsi.paren_depth = 0;
8402     efsi.pending_token.string = NULL;
8403     efsi.pending_token.string_length = 0;
8404     efsi.pending_token.token = 0;
8405 
8406     if (flags & (GRN_EXPR_SYNTAX_SCRIPT |
8407                  GRN_EXPR_SYNTAX_OUTPUT_COLUMNS |
8408                  GRN_EXPR_SYNTAX_ADJUSTER)) {
8409       efs_info *q = &efsi;
8410       if (flags & GRN_EXPR_SYNTAX_OUTPUT_COLUMNS) {
8411         PARSE(GRN_EXPR_TOKEN_START_OUTPUT_COLUMNS);
8412       } else if (flags & GRN_EXPR_SYNTAX_ADJUSTER) {
8413         PARSE(GRN_EXPR_TOKEN_START_ADJUSTER);
8414       }
8415       parse_script(ctx, &efsi);
8416     } else {
8417       parse_query(ctx, &efsi);
8418     }
8419 
8420     /*
8421         grn_obj strbuf;
8422         GRN_TEXT_INIT(&strbuf, 0);
8423         grn_expr_inspect_internal(ctx, &strbuf, expr);
8424         GRN_TEXT_PUTC(ctx, &strbuf, '\0');
8425         GRN_LOG(ctx, GRN_LOG_NOTICE, "query=(%s)", GRN_TEXT_VALUE(&strbuf));
8426         GRN_OBJ_FIN(ctx, &strbuf);
8427     */
8428 
8429     /*
8430     efsi.opt.vector_size = DEFAULT_WEIGHT_VECTOR_SIZE;
8431     efsi.opt.func = efsi.weight_set ? section_weight_cb : NULL;
8432     efsi.opt.func_arg = efsi.weight_set;
8433     efsi.snip_conds = NULL;
8434     */
8435     GRN_OBJ_FIN(ctx, &efsi.op_stack);
8436     GRN_OBJ_FIN(ctx, &efsi.mode_stack);
8437     GRN_OBJ_FIN(ctx, &efsi.max_interval_stack);
8438     GRN_OBJ_FIN(ctx, &efsi.similarity_threshold_stack);
8439     GRN_OBJ_FIN(ctx, &efsi.weight_stack);
8440     GRN_OBJ_FIN(ctx, &efsi.column_stack);
8441     GRN_OBJ_FIN(ctx, &efsi.token_stack);
8442     GRN_OBJ_FIN(ctx, &efsi.buf);
8443     if (efsi.object_literal) {
8444       grn_obj *value;
8445       GRN_HASH_EACH(ctx, efsi.object_literal, i, NULL, NULL, (void **)&value, {
8446         GRN_OBJ_FIN(ctx, value);
8447       });
8448       grn_hash_close(ctx, efsi.object_literal);
8449     }
8450   } else {
8451     ERR(GRN_INVALID_ARGUMENT, "variable is not defined correctly");
8452   }
8453   GRN_API_RETURN(ctx->rc);
8454 }
8455 
8456 grn_rc
grn_expr_parser_close(grn_ctx * ctx)8457 grn_expr_parser_close(grn_ctx *ctx)
8458 {
8459   if (ctx->impl->parser) {
8460     yyParser *parser = (yyParser *)ctx->impl->parser;
8461     ctx->impl->parser = NULL;
8462     grn_expr_parserFree(parser, free);
8463   }
8464   return ctx->rc;
8465 }
8466 
8467 typedef grn_rc (*grn_expr_syntax_expand_term_func)(grn_ctx *ctx,
8468                                                    const char *term,
8469                                                    unsigned int term_len,
8470                                                    grn_obj *substituted_term,
8471                                                    grn_user_data *user_data);
8472 static grn_rc
grn_expr_syntax_expand_term_by_func(grn_ctx * ctx,const char * term,unsigned int term_len,grn_obj * expanded_term,grn_user_data * user_data)8473 grn_expr_syntax_expand_term_by_func(grn_ctx *ctx,
8474                                     const char *term, unsigned int term_len,
8475                                     grn_obj *expanded_term,
8476                                     grn_user_data *user_data)
8477 {
8478   grn_rc rc;
8479   grn_obj *expander = user_data->ptr;
8480   grn_obj grn_term;
8481   grn_obj *caller;
8482   grn_obj *rc_object;
8483   int nargs = 0;
8484 
8485   GRN_TEXT_INIT(&grn_term, GRN_OBJ_DO_SHALLOW_COPY);
8486   GRN_TEXT_SET(ctx, &grn_term, term, term_len);
8487   grn_ctx_push(ctx, &grn_term);
8488   nargs++;
8489   grn_ctx_push(ctx, expanded_term);
8490   nargs++;
8491 
8492   caller = grn_expr_create(ctx, NULL, 0);
8493   rc = grn_proc_call(ctx, expander, nargs, caller);
8494   GRN_OBJ_FIN(ctx, &grn_term);
8495   rc_object = grn_ctx_pop(ctx);
8496   rc = GRN_INT32_VALUE(rc_object);
8497   grn_obj_unlink(ctx, caller);
8498 
8499   return rc;
8500 }
8501 
8502 typedef struct {
8503   grn_obj *table;
8504   grn_obj *column;
8505 } grn_expr_syntax_expand_term_by_column_data;
8506 
8507 static grn_rc
grn_expr_syntax_expand_term_by_column(grn_ctx * ctx,const char * term,unsigned int term_len,grn_obj * expanded_term,grn_user_data * user_data)8508 grn_expr_syntax_expand_term_by_column(grn_ctx *ctx,
8509                                       const char *term, unsigned int term_len,
8510                                       grn_obj *expanded_term,
8511                                       grn_user_data *user_data)
8512 {
8513   grn_rc rc = GRN_END_OF_DATA;
8514   grn_id id;
8515   grn_expr_syntax_expand_term_by_column_data *data = user_data->ptr;
8516   grn_obj *table, *column;
8517 
8518   table = data->table;
8519   column = data->column;
8520   if ((id = grn_table_get(ctx, table, term, term_len))) {
8521     if ((column->header.type == GRN_COLUMN_VAR_SIZE) &&
8522         ((column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR)) {
8523       unsigned int i, n;
8524       grn_obj values;
8525       GRN_TEXT_INIT(&values, GRN_OBJ_VECTOR);
8526       grn_obj_get_value(ctx, column, id, &values);
8527       n = grn_vector_size(ctx, &values);
8528       if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
8529       for (i = 0; i < n; i++) {
8530         const char *value;
8531         unsigned int length;
8532         if (i > 0) {
8533           GRN_TEXT_PUTS(ctx, expanded_term, " OR ");
8534         }
8535         if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
8536         length = grn_vector_get_element(ctx, &values, i, &value, NULL, NULL);
8537         GRN_TEXT_PUT(ctx, expanded_term, value, length);
8538         if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
8539       }
8540       if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
8541       GRN_OBJ_FIN(ctx, &values);
8542     } else {
8543       grn_obj_get_value(ctx, column, id, expanded_term);
8544     }
8545     rc = GRN_SUCCESS;
8546   }
8547   return rc;
8548 }
8549 
8550 typedef struct {
8551   grn_obj *table;
8552   grn_obj *term_column;
8553   grn_obj *expanded_term_column;
8554 } grn_expr_syntax_expand_term_by_table_data;
8555 
8556 static grn_rc
grn_expr_syntax_expand_term_by_table(grn_ctx * ctx,const char * term,unsigned int term_len,grn_obj * expanded_term,grn_user_data * user_data)8557 grn_expr_syntax_expand_term_by_table(grn_ctx *ctx,
8558                                      const char *term, unsigned int term_len,
8559                                      grn_obj *expanded_term,
8560                                      grn_user_data *user_data)
8561 {
8562   grn_rc rc = GRN_END_OF_DATA;
8563   grn_expr_syntax_expand_term_by_table_data *data = user_data->ptr;
8564   grn_obj *table;
8565   grn_obj *term_column;
8566   grn_obj *expanded_term_column;
8567   grn_obj *expression;
8568   grn_obj *variable;
8569   grn_obj *found_terms;
8570   int n_terms;
8571 
8572   table = data->table;
8573   term_column = data->term_column;
8574   expanded_term_column = data->expanded_term_column;
8575 
8576   GRN_EXPR_CREATE_FOR_QUERY(ctx, table, expression, variable);
8577   if (ctx->rc != GRN_SUCCESS) {
8578     ERR(ctx->rc,
8579         "[query][expand][table] "
8580         "failed to create expression: <%s>",
8581         ctx->errbuf);
8582     return ctx->rc;
8583   }
8584   grn_expr_append_const(ctx, expression, term_column, GRN_OP_GET_VALUE, 1);
8585   grn_expr_append_const_str(ctx, expression, term, term_len, GRN_OP_PUSH, 1);
8586   grn_expr_append_op(ctx, expression, GRN_OP_EQUAL, 2);
8587   if (ctx->rc != GRN_SUCCESS) {
8588     grn_obj_close(ctx, expression);
8589     ERR(ctx->rc,
8590         "[query][expand][table] "
8591         "failed to build expression: <%s>",
8592         ctx->errbuf);
8593     return ctx->rc;
8594   }
8595 
8596   found_terms = grn_table_select(ctx, table, expression, NULL, GRN_OP_OR);
8597   grn_obj_close(ctx, expression);
8598   if (!found_terms) {
8599     ERR(ctx->rc,
8600         "[query][expand][table] "
8601         "failed to find term: <%.*s>: <%s>",
8602         (int)term_len,
8603         term,
8604         ctx->errbuf);
8605     return ctx->rc;
8606   }
8607 
8608   n_terms = grn_table_size(ctx, found_terms);
8609   if (n_terms == 0) {
8610     grn_obj_close(ctx, found_terms);
8611     return rc;
8612   }
8613 
8614   {
8615     int nth_term;
8616 
8617     GRN_TEXT_PUTC(ctx, expanded_term, '(');
8618     nth_term = 0;
8619     GRN_TABLE_EACH_BEGIN(ctx, found_terms, cursor, id) {
8620       void *key;
8621       grn_id record_id;
8622 
8623       grn_table_cursor_get_key(ctx, cursor, &key);
8624       record_id = *((grn_id *)key);
8625       if (grn_obj_is_vector_column(ctx, expanded_term_column)) {
8626         unsigned int j, n_values;
8627         grn_obj values;
8628         GRN_TEXT_INIT(&values, GRN_OBJ_VECTOR);
8629         grn_obj_get_value(ctx, expanded_term_column, record_id, &values);
8630         n_values = grn_vector_size(ctx, &values);
8631         n_terms += n_values - 1;
8632         for (j = 0; j < n_values; j++) {
8633           const char *value;
8634           unsigned int length;
8635           if (nth_term > 0) {
8636             GRN_TEXT_PUTS(ctx, expanded_term, " OR ");
8637           }
8638           if (n_terms > 1) {
8639             GRN_TEXT_PUTC(ctx, expanded_term, '(');
8640           }
8641           length = grn_vector_get_element(ctx, &values, j, &value, NULL, NULL);
8642           GRN_TEXT_PUT(ctx, expanded_term, value, length);
8643           if (n_terms > 1) {
8644             GRN_TEXT_PUTC(ctx, expanded_term, ')');
8645           }
8646           nth_term++;
8647         }
8648         GRN_OBJ_FIN(ctx, &values);
8649       } else {
8650         if (nth_term > 0) {
8651           GRN_TEXT_PUTS(ctx, expanded_term, " OR ");
8652         }
8653         if (n_terms > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
8654         grn_obj_get_value(ctx, expanded_term_column, record_id, expanded_term);
8655         if (n_terms > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
8656         nth_term++;
8657       }
8658     } GRN_TABLE_EACH_END(ctx, cursor);
8659     GRN_TEXT_PUTC(ctx, expanded_term, ')');
8660   }
8661   rc = GRN_SUCCESS;
8662   grn_obj_close(ctx, found_terms);
8663 
8664   return rc;
8665 }
8666 
8667 static grn_rc
grn_expr_syntax_expand_query_terms(grn_ctx * ctx,const char * query,unsigned int query_size,grn_expr_flags flags,grn_obj * expanded_query,grn_expr_syntax_expand_term_func expand_term_func,grn_user_data * user_data)8668 grn_expr_syntax_expand_query_terms(grn_ctx *ctx,
8669                                    const char *query, unsigned int query_size,
8670                                    grn_expr_flags flags,
8671                                    grn_obj *expanded_query,
8672                                    grn_expr_syntax_expand_term_func expand_term_func,
8673                                    grn_user_data *user_data)
8674 {
8675   grn_obj buf;
8676   unsigned int len;
8677   const char *start, *cur = query, *query_end = query + (size_t)query_size;
8678   GRN_TEXT_INIT(&buf, 0);
8679   for (;;) {
8680     while (cur < query_end && grn_isspace(cur, ctx->encoding)) {
8681       if (!(len = grn_charlen(ctx, cur, query_end))) { goto exit; }
8682       GRN_TEXT_PUT(ctx, expanded_query, cur, len);
8683       cur += len;
8684     }
8685     if (query_end <= cur) { break; }
8686     switch (*cur) {
8687     case '\0' :
8688       goto exit;
8689       break;
8690     case GRN_QUERY_AND :
8691     case GRN_QUERY_ADJ_INC :
8692     case GRN_QUERY_ADJ_DEC :
8693     case GRN_QUERY_ADJ_NEG :
8694     case GRN_QUERY_AND_NOT :
8695     case GRN_QUERY_PARENL :
8696     case GRN_QUERY_PARENR :
8697     case GRN_QUERY_PREFIX :
8698       GRN_TEXT_PUTC(ctx, expanded_query, *cur);
8699       cur++;
8700       break;
8701     case GRN_QUERY_QUOTEL :
8702       GRN_BULK_REWIND(&buf);
8703       for (start = cur++; cur < query_end; cur += len) {
8704         if (!(len = grn_charlen(ctx, cur, query_end))) {
8705           goto exit;
8706         } else if (len == 1) {
8707           if (*cur == GRN_QUERY_QUOTER) {
8708             cur++;
8709             break;
8710           } else if (cur + 1 < query_end && *cur == GRN_QUERY_ESCAPE) {
8711             cur++;
8712             len = grn_charlen(ctx, cur, query_end);
8713           }
8714         }
8715         GRN_TEXT_PUT(ctx, &buf, cur, len);
8716       }
8717       if (expand_term_func(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf),
8718                            expanded_query, user_data)) {
8719         GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
8720       }
8721       break;
8722     case 'O' :
8723       if (cur + 2 <= query_end && cur[1] == 'R' &&
8724           (cur + 2 == query_end || grn_isspace(cur + 2, ctx->encoding))) {
8725         GRN_TEXT_PUT(ctx, expanded_query, cur, 2);
8726         cur += 2;
8727         break;
8728       }
8729       /* fallthru */
8730     default :
8731       for (start = cur; cur < query_end; cur += len) {
8732         if (!(len = grn_charlen(ctx, cur, query_end))) {
8733           goto exit;
8734         } else if (grn_isspace(cur, ctx->encoding)) {
8735           break;
8736         } else if (len == 1) {
8737           if (*cur == GRN_QUERY_PARENL ||
8738               *cur == GRN_QUERY_PARENR ||
8739               *cur == GRN_QUERY_PREFIX) {
8740             break;
8741           } else if (flags & GRN_EXPR_ALLOW_COLUMN && *cur == GRN_QUERY_COLUMN) {
8742             if (cur + 1 < query_end) {
8743               switch (cur[1]) {
8744               case '!' :
8745               case '@' :
8746               case '^' :
8747               case '$' :
8748                 cur += 2;
8749                 break;
8750               case '=' :
8751                 cur += (flags & GRN_EXPR_ALLOW_UPDATE) ? 2 : 1;
8752                 break;
8753               case '<' :
8754               case '>' :
8755                 cur += (cur + 2 < query_end && cur[2] == '=') ? 3 : 2;
8756                 break;
8757               default :
8758                 cur += 1;
8759                 break;
8760               }
8761             } else {
8762               cur += 1;
8763             }
8764             GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
8765             start = cur;
8766             break;
8767           }
8768         }
8769       }
8770       if (start < cur) {
8771         if (expand_term_func(ctx, start, cur - start,
8772                              expanded_query, user_data)) {
8773           GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
8774         }
8775       }
8776       break;
8777     }
8778   }
8779 exit :
8780   GRN_OBJ_FIN(ctx, &buf);
8781   return GRN_SUCCESS;
8782 }
8783 
8784 grn_rc
grn_expr_syntax_expand_query(grn_ctx * ctx,const char * query,int query_size,grn_expr_flags flags,grn_obj * expander,grn_obj * expanded_query)8785 grn_expr_syntax_expand_query(grn_ctx *ctx,
8786                              const char *query, int query_size,
8787                              grn_expr_flags flags,
8788                              grn_obj *expander,
8789                              grn_obj *expanded_query)
8790 {
8791   GRN_API_ENTER;
8792 
8793   if (query_size < 0) {
8794     query_size = strlen(query);
8795   }
8796 
8797   switch (expander->header.type) {
8798   case GRN_PROC :
8799     if (((grn_proc *)expander)->type == GRN_PROC_FUNCTION) {
8800       grn_user_data user_data;
8801       user_data.ptr = expander;
8802       grn_expr_syntax_expand_query_terms(ctx,
8803                                          query, query_size,
8804                                          flags,
8805                                          expanded_query,
8806                                          grn_expr_syntax_expand_term_by_func,
8807                                          &user_data);
8808     } else {
8809       char name[GRN_TABLE_MAX_KEY_SIZE];
8810       int name_size;
8811       name_size = grn_obj_name(ctx, expander, name, GRN_TABLE_MAX_KEY_SIZE);
8812       ERR(GRN_INVALID_ARGUMENT,
8813           "[query][expand][proc] "
8814           "proc query expander must be a function proc: <%.*s>",
8815           name_size, name);
8816     }
8817     break;
8818   case GRN_COLUMN_FIX_SIZE :
8819   case GRN_COLUMN_VAR_SIZE :
8820     {
8821       grn_obj *expansion_table;
8822       expansion_table = grn_column_table(ctx, expander);
8823       if (expansion_table) {
8824         grn_user_data user_data;
8825         grn_expr_syntax_expand_term_by_column_data data;
8826         user_data.ptr = &data;
8827         data.table = expansion_table;
8828         data.column = expander;
8829         grn_expr_syntax_expand_query_terms(ctx,
8830                                            query, query_size,
8831                                            flags,
8832                                            expanded_query,
8833                                            grn_expr_syntax_expand_term_by_column,
8834                                            &user_data);
8835       } else {
8836         char name[GRN_TABLE_MAX_KEY_SIZE];
8837         int name_size;
8838         name_size = grn_obj_name(ctx, expander, name, GRN_TABLE_MAX_KEY_SIZE);
8839         ERR(GRN_INVALID_ARGUMENT,
8840             "[query][expand][column] "
8841             "failed to get table of query expansion column: <%.*s>",
8842             name_size, name);
8843       }
8844     }
8845     break;
8846   default :
8847     {
8848       char name[GRN_TABLE_MAX_KEY_SIZE];
8849       int name_size;
8850       grn_obj type_name;
8851 
8852       name_size = grn_obj_name(ctx, expander, name, GRN_TABLE_MAX_KEY_SIZE);
8853       GRN_TEXT_INIT(&type_name, 0);
8854       grn_inspect_type(ctx, &type_name, expander->header.type);
8855       ERR(GRN_INVALID_ARGUMENT,
8856           "[query][expand] "
8857           "query expander must be a data column or function proc: <%.*s>(%.*s)",
8858           name_size, name,
8859           (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
8860       GRN_OBJ_FIN(ctx, &type_name);
8861     }
8862     break;
8863   }
8864 
8865   GRN_API_RETURN(ctx->rc);
8866 }
8867 
8868 grn_rc
grn_expr_syntax_expand_query_by_table(grn_ctx * ctx,const char * query,int query_size,grn_expr_flags flags,grn_obj * term_column,grn_obj * expanded_term_column,grn_obj * expanded_query)8869 grn_expr_syntax_expand_query_by_table(grn_ctx *ctx,
8870                                       const char *query, int query_size,
8871                                       grn_expr_flags flags,
8872                                       grn_obj *term_column,
8873                                       grn_obj *expanded_term_column,
8874                                       grn_obj *expanded_query)
8875 {
8876   grn_obj *table;
8877   grn_bool term_column_is_key;
8878 
8879   GRN_API_ENTER;
8880 
8881   if (query_size < 0) {
8882     query_size = strlen(query);
8883   }
8884 
8885   if (!grn_obj_is_data_column(ctx, expanded_term_column)) {
8886     grn_obj inspected;
8887     GRN_TEXT_INIT(&inspected, 0);
8888     grn_inspect(ctx, &inspected, expanded_term_column);
8889     ERR(GRN_INVALID_ARGUMENT,
8890         "[query][expand][table] "
8891         "expanded term column must be a data column: <%.*s>",
8892         (int)GRN_TEXT_LEN(&inspected),
8893         GRN_TEXT_VALUE(&inspected));
8894     GRN_OBJ_FIN(ctx, &inspected);
8895     GRN_API_RETURN(ctx->rc);
8896   }
8897   table = grn_column_table(ctx, expanded_term_column);
8898 
8899   if (!term_column) {
8900     term_column_is_key = GRN_TRUE;
8901   } else {
8902     if (grn_obj_is_key_accessor(ctx, term_column)) {
8903       term_column_is_key = GRN_TRUE;
8904     } else if (grn_obj_is_data_column(ctx, term_column)) {
8905       term_column_is_key = GRN_FALSE;
8906     } else {
8907       grn_obj inspected;
8908       GRN_TEXT_INIT(&inspected, 0);
8909       grn_inspect(ctx, &inspected, term_column);
8910       ERR(GRN_INVALID_ARGUMENT,
8911           "[query][expand][table] "
8912           "term column must be NULL, _key or a data column: <%.*s>",
8913           (int)GRN_TEXT_LEN(&inspected),
8914           GRN_TEXT_VALUE(&inspected));
8915       GRN_OBJ_FIN(ctx, &inspected);
8916       GRN_API_RETURN(ctx->rc);
8917     }
8918     if (term_column->header.domain != expanded_term_column->header.domain) {
8919       grn_obj inspected_term_column;
8920       grn_obj inspected_expanded_term_column;
8921       GRN_TEXT_INIT(&inspected_term_column, 0);
8922       GRN_TEXT_INIT(&inspected_expanded_term_column, 0);
8923       grn_inspect(ctx, &inspected_term_column, term_column);
8924       grn_inspect(ctx, &inspected_expanded_term_column, expanded_term_column);
8925       ERR(GRN_INVALID_ARGUMENT,
8926           "[query][expand][table] "
8927           "term column and expanded term column must belong to the same table: "
8928           "term column: <%.*s>, "
8929           "expanded term column: <%*.s>",
8930           (int)GRN_TEXT_LEN(&inspected_term_column),
8931           GRN_TEXT_VALUE(&inspected_term_column),
8932           (int)GRN_TEXT_LEN(&inspected_expanded_term_column),
8933           GRN_TEXT_VALUE(&inspected_expanded_term_column));
8934       GRN_OBJ_FIN(ctx, &inspected_term_column);
8935       GRN_OBJ_FIN(ctx, &inspected_expanded_term_column);
8936       GRN_API_RETURN(ctx->rc);
8937     }
8938   }
8939 
8940   if (term_column_is_key) {
8941     grn_user_data user_data;
8942     grn_expr_syntax_expand_term_by_column_data data;
8943     user_data.ptr = &data;
8944     data.table = table;
8945     data.column = expanded_term_column;
8946     grn_expr_syntax_expand_query_terms(ctx,
8947                                        query, query_size,
8948                                        flags,
8949                                        expanded_query,
8950                                        grn_expr_syntax_expand_term_by_column,
8951                                        &user_data);
8952   } else {
8953     grn_user_data user_data;
8954     grn_expr_syntax_expand_term_by_table_data data;
8955     user_data.ptr = &data;
8956     data.table = table;
8957     data.term_column = term_column;
8958     data.expanded_term_column = expanded_term_column;
8959     grn_expr_syntax_expand_query_terms(ctx,
8960                                        query, query_size,
8961                                        flags,
8962                                        expanded_query,
8963                                        grn_expr_syntax_expand_term_by_table,
8964                                        &user_data);
8965   }
8966 
8967   GRN_API_RETURN(ctx->rc);
8968 }
8969 
8970 grn_rc
grn_expr_get_keywords(grn_ctx * ctx,grn_obj * expr,grn_obj * keywords)8971 grn_expr_get_keywords(grn_ctx *ctx, grn_obj *expr, grn_obj *keywords)
8972 {
8973   int i, n;
8974   scan_info **sis, *si;
8975   GRN_API_ENTER;
8976   if ((sis = grn_scan_info_build(ctx, expr, &n, GRN_OP_OR, GRN_FALSE))) {
8977     int butp = 0, nparens = 0, npbut = 0;
8978     grn_obj but_stack;
8979     GRN_UINT32_INIT(&but_stack, GRN_OBJ_VECTOR);
8980     for (i = n; i--;) {
8981       si = sis[i];
8982       if (si->flags & SCAN_POP) {
8983         nparens++;
8984         if (si->logical_op == GRN_OP_AND_NOT) {
8985           GRN_UINT32_PUT(ctx, &but_stack, npbut);
8986           npbut = nparens;
8987           butp = 1 - butp;
8988         }
8989       } else {
8990         if (butp == (si->logical_op == GRN_OP_AND_NOT) &&
8991             si->query) {
8992           switch (si->op) {
8993           case GRN_OP_MATCH :
8994             if (keywords->header.type == GRN_PVECTOR) {
8995               GRN_PTR_PUT(ctx, keywords, si->query);
8996             } else {
8997               grn_vector_add_element(ctx,
8998                                      keywords,
8999                                      GRN_TEXT_VALUE(si->query),
9000                                      GRN_TEXT_LEN(si->query),
9001                                      0,
9002                                      GRN_DB_TEXT);
9003             }
9004             break;
9005           case GRN_OP_SIMILAR :
9006             if (keywords->header.type == GRN_VECTOR &&
9007                 GRN_BULK_VSIZE(&(si->index)) > 0) {
9008               grn_token_cursor *token_cursor;
9009               unsigned int token_flags = 0;
9010               grn_obj *index = GRN_PTR_VALUE(&(si->index));
9011               grn_obj *lexicon;
9012 
9013               lexicon = grn_ctx_at(ctx, index->header.domain);
9014               token_cursor = grn_token_cursor_open(ctx,
9015                                                    lexicon,
9016                                                    GRN_TEXT_VALUE(si->query),
9017                                                    GRN_TEXT_LEN(si->query),
9018                                                    GRN_TOKENIZE_GET,
9019                                                    token_flags);
9020               if (token_cursor) {
9021                 grn_obj *source_table;
9022                 uint32_t n_records_threshold;
9023                 source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, index));
9024                 n_records_threshold = grn_table_size(ctx, source_table) / 2;
9025                 while (token_cursor->status != GRN_TOKEN_CURSOR_DONE) {
9026                   grn_id token_id;
9027                   uint32_t n_estimated_records;
9028                   token_id = grn_token_cursor_next(ctx, token_cursor);
9029                   if (token_id == GRN_ID_NIL) {
9030                     continue;
9031                   }
9032                   n_estimated_records =
9033                     grn_ii_estimate_size(ctx, (grn_ii *)index, token_id);
9034                   if (n_estimated_records >= n_records_threshold) {
9035                     continue;
9036                   }
9037                   grn_vector_add_element(ctx,
9038                                          keywords,
9039                                          token_cursor->curr,
9040                                          token_cursor->curr_size,
9041                                          0,
9042                                          GRN_DB_TEXT);
9043                 }
9044                 grn_token_cursor_close(ctx, token_cursor);
9045               }
9046             }
9047             break;
9048           default :
9049             break;
9050           }
9051         }
9052         if (si->flags & SCAN_PUSH) {
9053           if (nparens == npbut) {
9054             butp = 1 - butp;
9055             GRN_UINT32_POP(&but_stack, npbut);
9056           }
9057           nparens--;
9058         }
9059       }
9060     }
9061     GRN_OBJ_FIN(ctx, &but_stack);
9062     for (i = n; i--;) { SI_FREE(sis[i]); }
9063     GRN_FREE(sis);
9064   }
9065   GRN_API_RETURN(GRN_SUCCESS);
9066 }
9067 
9068 grn_rc
grn_expr_snip_add_conditions(grn_ctx * ctx,grn_obj * expr,grn_obj * snip,unsigned int n_tags,const char ** opentags,unsigned int * opentag_lens,const char ** closetags,unsigned int * closetag_lens)9069 grn_expr_snip_add_conditions(grn_ctx *ctx, grn_obj *expr, grn_obj *snip,
9070                              unsigned int n_tags,
9071                              const char **opentags, unsigned int *opentag_lens,
9072                              const char **closetags, unsigned int *closetag_lens)
9073 {
9074   grn_rc rc;
9075   grn_obj keywords;
9076 
9077   GRN_API_ENTER;
9078 
9079   GRN_PTR_INIT(&keywords, GRN_OBJ_VECTOR, GRN_ID_NIL);
9080   rc = grn_expr_get_keywords(ctx, expr, &keywords);
9081   if (rc != GRN_SUCCESS) {
9082     GRN_OBJ_FIN(ctx, &keywords);
9083     GRN_API_RETURN(rc);
9084   }
9085 
9086   if (n_tags) {
9087     int i;
9088     for (i = 0;; i = (i + 1) % n_tags) {
9089       grn_obj *keyword;
9090       GRN_PTR_POP(&keywords, keyword);
9091       if (!keyword) { break; }
9092       grn_snip_add_cond(ctx, snip,
9093                         GRN_TEXT_VALUE(keyword), GRN_TEXT_LEN(keyword),
9094                         opentags[i], opentag_lens[i],
9095                         closetags[i], closetag_lens[i]);
9096     }
9097   } else {
9098     for (;;) {
9099       grn_obj *keyword;
9100       GRN_PTR_POP(&keywords, keyword);
9101       if (!keyword) { break; }
9102       grn_snip_add_cond(ctx, snip,
9103                         GRN_TEXT_VALUE(keyword), GRN_TEXT_LEN(keyword),
9104                         NULL, 0, NULL, 0);
9105     }
9106   }
9107   GRN_OBJ_FIN(ctx, &keywords);
9108 
9109   GRN_API_RETURN(GRN_SUCCESS);
9110 }
9111 
9112 grn_obj *
grn_expr_snip(grn_ctx * ctx,grn_obj * expr,int flags,unsigned int width,unsigned int max_results,unsigned int n_tags,const char ** opentags,unsigned int * opentag_lens,const char ** closetags,unsigned int * closetag_lens,grn_snip_mapping * mapping)9113 grn_expr_snip(grn_ctx *ctx, grn_obj *expr, int flags,
9114               unsigned int width, unsigned int max_results,
9115               unsigned int n_tags,
9116               const char **opentags, unsigned int *opentag_lens,
9117               const char **closetags, unsigned int *closetag_lens,
9118               grn_snip_mapping *mapping)
9119 {
9120   grn_obj *res = NULL;
9121   GRN_API_ENTER;
9122   if ((res = grn_snip_open(ctx, flags, width, max_results,
9123                            NULL, 0, NULL, 0, mapping))) {
9124     grn_expr_snip_add_conditions(ctx, expr, res,
9125                                  n_tags,
9126                                  opentags, opentag_lens,
9127                                  closetags, closetag_lens);
9128   }
9129   GRN_API_RETURN(res);
9130 }
9131 
9132 /*
9133   So far, grn_column_filter() is nothing but a very rough prototype.
9134   Although GRN_COLUMN_EACH() can accelerate many range queries,
9135   the following stuff must be resolved one by one.
9136 
9137   * support accessors as column
9138   * support tables which have deleted records
9139   * support various operators
9140   * support various column types
9141 */
9142 grn_rc
grn_column_filter(grn_ctx * ctx,grn_obj * column,grn_operator operator,grn_obj * value,grn_obj * result_set,grn_operator set_operation)9143 grn_column_filter(grn_ctx *ctx, grn_obj *column,
9144                   grn_operator operator,
9145                   grn_obj *value, grn_obj *result_set,
9146                   grn_operator set_operation)
9147 {
9148   uint32_t *vp;
9149   grn_posting posting;
9150   uint32_t value_ = grn_atoui(GRN_TEXT_VALUE(value), GRN_BULK_CURR(value), NULL);
9151   posting.sid = 1;
9152   posting.pos = 0;
9153   posting.weight = 0;
9154   GRN_COLUMN_EACH(ctx, column, id, vp, {
9155     if (*vp < value_) {
9156       posting.rid = id;
9157       grn_ii_posting_add(ctx, &posting, (grn_hash *)result_set, set_operation);
9158     }
9159   });
9160   grn_ii_resolve_sel_and(ctx, (grn_hash *)result_set, set_operation);
9161   return ctx->rc;
9162 }
9163 
9164 grn_rc
grn_expr_syntax_escape(grn_ctx * ctx,const char * string,int string_size,const char * target_characters,char escape_character,grn_obj * escaped_string)9165 grn_expr_syntax_escape(grn_ctx *ctx, const char *string, int string_size,
9166                        const char *target_characters,
9167                        char escape_character,
9168                        grn_obj *escaped_string)
9169 {
9170   grn_rc rc = GRN_SUCCESS;
9171   const char *current, *string_end;
9172 
9173   if (!string) {
9174     return GRN_INVALID_ARGUMENT;
9175   }
9176 
9177   GRN_API_ENTER;
9178   if (string_size < 0) {
9179     string_size = strlen(string);
9180   }
9181   string_end = string + string_size;
9182 
9183   current = string;
9184   while (current < string_end) {
9185     unsigned int char_size;
9186     char_size = grn_charlen(ctx, current, string_end);
9187     switch (char_size) {
9188     case 0 :
9189       /* string includes malformed multibyte character. */
9190       return GRN_INVALID_ARGUMENT;
9191       break;
9192     case 1 :
9193       if (strchr(target_characters, *current)) {
9194         GRN_TEXT_PUTC(ctx, escaped_string, escape_character);
9195       }
9196       GRN_TEXT_PUT(ctx, escaped_string, current, char_size);
9197       current += char_size;
9198       break;
9199     default :
9200       GRN_TEXT_PUT(ctx, escaped_string, current, char_size);
9201       current += char_size;
9202       break;
9203     }
9204   }
9205 
9206   GRN_API_RETURN(rc);
9207 }
9208 
9209 grn_rc
grn_expr_syntax_escape_query(grn_ctx * ctx,const char * query,int query_size,grn_obj * escaped_query)9210 grn_expr_syntax_escape_query(grn_ctx *ctx, const char *query, int query_size,
9211                              grn_obj *escaped_query)
9212 {
9213   const char target_characters[] = {
9214     GRN_QUERY_AND,
9215     GRN_QUERY_AND_NOT,
9216     GRN_QUERY_ADJ_INC,
9217     GRN_QUERY_ADJ_DEC,
9218     GRN_QUERY_ADJ_NEG,
9219     GRN_QUERY_PREFIX,
9220     GRN_QUERY_PARENL,
9221     GRN_QUERY_PARENR,
9222     GRN_QUERY_QUOTEL,
9223     GRN_QUERY_ESCAPE,
9224     GRN_QUERY_COLUMN,
9225     '\0',
9226   };
9227   return grn_expr_syntax_escape(ctx, query, query_size,
9228                                 target_characters, GRN_QUERY_ESCAPE,
9229                                 escaped_query);
9230 }
9231 
9232 grn_rc
grn_expr_dump_plan(grn_ctx * ctx,grn_obj * expr,grn_obj * buffer)9233 grn_expr_dump_plan(grn_ctx *ctx, grn_obj *expr, grn_obj *buffer)
9234 {
9235   int n;
9236   scan_info **sis;
9237 
9238   GRN_API_ENTER;
9239   sis = grn_scan_info_build(ctx, expr, &n, GRN_OP_OR, GRN_FALSE);
9240   if (sis) {
9241     int i;
9242     grn_inspect_scan_info_list(ctx, buffer, sis, n);
9243     for (i = 0; i < n; i++) {
9244       SI_FREE(sis[i]);
9245     }
9246     GRN_FREE(sis);
9247   } else {
9248     GRN_TEXT_PUTS(ctx, buffer, "sequential search\n");
9249   }
9250   GRN_API_RETURN(GRN_SUCCESS);
9251 }
9252 
9253 static unsigned int
grn_expr_estimate_size_raw(grn_ctx * ctx,grn_obj * expr,grn_obj * table)9254 grn_expr_estimate_size_raw(grn_ctx *ctx, grn_obj *expr, grn_obj *table)
9255 {
9256   return grn_table_size(ctx, table);
9257 }
9258 
9259 unsigned int
grn_expr_estimate_size(grn_ctx * ctx,grn_obj * expr)9260 grn_expr_estimate_size(grn_ctx *ctx, grn_obj *expr)
9261 {
9262   grn_obj *table;
9263   grn_obj *variable;
9264   unsigned int size;
9265 
9266   variable = grn_expr_get_var_by_offset(ctx, expr, 0);
9267   if (!variable) {
9268     ERR(GRN_INVALID_ARGUMENT, "at least one variable must be defined");
9269     return 0;
9270   }
9271 
9272   table = grn_ctx_at(ctx, variable->header.domain);
9273   if (!table) {
9274     ERR(GRN_INVALID_ARGUMENT,
9275         "variable refers unknown domain: <%u>", variable->header.domain);
9276     return 0;
9277   }
9278 
9279   GRN_API_ENTER;
9280 #ifdef GRN_WITH_MRUBY
9281   grn_ctx_impl_mrb_ensure_init(ctx);
9282   if (ctx->rc != GRN_SUCCESS) {
9283     GRN_API_RETURN(0);
9284   }
9285   if (ctx->impl->mrb.state) {
9286     size = grn_mrb_expr_estimate_size(ctx, expr, table);
9287   } else {
9288     size = grn_expr_estimate_size_raw(ctx, expr, table);
9289   }
9290 #else
9291   size = grn_expr_estimate_size_raw(ctx, expr, table);
9292 #endif
9293   GRN_API_RETURN(size);
9294 }
9295