1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2009-2017 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "grn_proc.h"
20#include "grn_ctx.h"
21#include "grn_ii.h"
22#include "grn_db.h"
23#include "grn_util.h"
24#include "grn_output.h"
25#include "grn_pat.h"
26#include "grn_geo.h"
27#include "grn_expr.h"
28#include "grn_cache.h"
29#include "grn_load.h"
30
31#include <string.h>
32#include <stdlib.h>
33#include <fcntl.h>
34#include <sys/stat.h>
35
36#ifdef WIN32
37# include <io.h>
38# include <share.h>
39#endif /* WIN32 */
40
41#ifndef O_NOFOLLOW
42#define O_NOFOLLOW 0
43#endif
44
45/**** globals for procs ****/
46const char *grn_document_root = NULL;
47
48#define VAR GRN_PROC_GET_VAR_BY_OFFSET
49
50static double grn_between_too_many_index_match_ratio = 0.01;
51static double grn_in_values_too_many_index_match_ratio = 0.01;
52
53void
54grn_proc_init_from_env(void)
55{
56 {
57 char grn_between_too_many_index_match_ratio_env[GRN_ENV_BUFFER_SIZE];
58 grn_getenv("GRN_BETWEEN_TOO_MANY_INDEX_MATCH_RATIO",
59 grn_between_too_many_index_match_ratio_env,
60 GRN_ENV_BUFFER_SIZE);
61 if (grn_between_too_many_index_match_ratio_env[0]) {
62 grn_between_too_many_index_match_ratio =
63 atof(grn_between_too_many_index_match_ratio_env);
64 }
65 }
66
67 {
68 char grn_in_values_too_many_index_match_ratio_env[GRN_ENV_BUFFER_SIZE];
69 grn_getenv("GRN_IN_VALUES_TOO_MANY_INDEX_MATCH_RATIO",
70 grn_in_values_too_many_index_match_ratio_env,
71 GRN_ENV_BUFFER_SIZE);
72 if (grn_in_values_too_many_index_match_ratio_env[0]) {
73 grn_in_values_too_many_index_match_ratio =
74 atof(grn_in_values_too_many_index_match_ratio_env);
75 }
76 }
77}
78
79/* bulk must be initialized grn_bulk or grn_msg */
80static int
81grn_bulk_put_from_file(grn_ctx *ctx, grn_obj *bulk, const char *path)
82{
83 /* FIXME: implement more smartly with grn_bulk */
84 int fd, ret = 0;
85 struct stat stat;
86 grn_open(fd, path, O_RDONLY|O_NOFOLLOW|GRN_OPEN_FLAG_BINARY);
87 if (fd == -1) {
88 switch (errno) {
89 case EACCES :
90 ERR(GRN_OPERATION_NOT_PERMITTED, "request is not allowed: <%s>", path);
91 break;
92 case ENOENT :
93 ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY, "no such file: <%s>", path);
94 break;
95#ifndef WIN32
96 case ELOOP :
97 ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY,
98 "symbolic link is not allowed: <%s>", path);
99 break;
100#endif /* WIN32 */
101 default :
102 ERRNO_ERR("failed to open file: <%s>", path);
103 break;
104 }
105 return 0;
106 }
107 if (fstat(fd, &stat) != -1) {
108 char *buf, *bp;
109 off_t rest = stat.st_size;
110 if ((buf = GRN_MALLOC(rest))) {
111 ssize_t ss;
112 for (bp = buf; rest; rest -= ss, bp += ss) {
113 if ((ss = grn_read(fd, bp, rest)) == -1) { goto exit; }
114 }
115 GRN_TEXT_PUT(ctx, bulk, buf, stat.st_size);
116 ret = 1;
117 }
118 GRN_FREE(buf);
119 } else {
120 ERR(GRN_INVALID_ARGUMENT, "cannot stat file: <%s>", path);
121 }
122exit :
123 grn_close(fd);
124 return ret;
125}
126
127#ifdef stat
128# undef stat
129#endif /* stat */
130
131/**** procs ****/
132
133static grn_obj *
134proc_load(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
135{
136 grn_load_input input;
137
138 input.type = grn_plugin_proc_get_var_content_type(ctx,
139 user_data,
140 "input_type",
141 -1,
142 GRN_CONTENT_JSON);
143#define INIT_STRING_ARGUMENT(member_name, arg_name) \
144 input.member_name.value = \
145 grn_plugin_proc_get_var_string(ctx, \
146 user_data, \
147 arg_name, \
148 -1, \
149 &(input.member_name.length))
150
151 INIT_STRING_ARGUMENT(table, "table");
152 INIT_STRING_ARGUMENT(columns, "columns");
153 INIT_STRING_ARGUMENT(values, "values");
154 INIT_STRING_ARGUMENT(if_exists, "ifexists");
155 INIT_STRING_ARGUMENT(each, "each");
156
157#undef INIT_STRING_ARGUMENT
158
159 input.output_ids = grn_plugin_proc_get_var_bool(ctx,
160 user_data,
161 "output_ids", -1,
162 GRN_FALSE);
163 input.output_errors = grn_plugin_proc_get_var_bool(ctx,
164 user_data,
165 "output_errors", -1,
166 GRN_FALSE);
167 input.emit_level = 1;
168
169 grn_load_internal(ctx, &input);
170 if (ctx->rc == GRN_CANCEL) {
171 ctx->impl->loader.stat = GRN_LOADER_END;
172 ctx->impl->loader.rc = GRN_SUCCESS;
173 }
174 if (ctx->impl->loader.stat != GRN_LOADER_END &&
175 !(ctx->impl->command.flags & GRN_CTX_TAIL)) {
176 grn_obj *command = grn_proc_get_info(ctx, user_data, NULL, NULL, NULL);
177 grn_ctx_set_keep_command(ctx, command);
178 } else {
179 if (ctx->impl->loader.rc != GRN_SUCCESS) {
180 ctx->rc = ctx->impl->loader.rc;
181 grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, ctx->impl->loader.errbuf);
182 }
183 if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
184 int n_elements = 1;
185 if (ctx->impl->loader.output_ids) {
186 n_elements++;
187 }
188 if (ctx->impl->loader.output_errors) {
189 n_elements++;
190 }
191 GRN_OUTPUT_MAP_OPEN("result", n_elements);
192 GRN_OUTPUT_CSTR("n_loaded_records");
193 GRN_OUTPUT_INT64(ctx->impl->loader.nrecords);
194 if (ctx->impl->loader.output_ids) {
195 grn_obj *ids = &(ctx->impl->loader.ids);
196 int i, n_ids;
197
198 GRN_OUTPUT_CSTR("loaded_ids");
199 n_ids = GRN_BULK_VSIZE(ids) / sizeof(uint32_t);
200 GRN_OUTPUT_ARRAY_OPEN("loaded_ids", n_ids);
201 for (i = 0; i < n_ids; i++) {
202 GRN_OUTPUT_UINT64(GRN_UINT32_VALUE_AT(ids, i));
203 }
204 GRN_OUTPUT_ARRAY_CLOSE();
205 }
206 if (ctx->impl->loader.output_errors) {
207 grn_obj *return_codes = &(ctx->impl->loader.return_codes);
208 grn_obj *error_messages = &(ctx->impl->loader.error_messages);
209 int i, n;
210
211 GRN_OUTPUT_CSTR("errors");
212 n = GRN_BULK_VSIZE(return_codes) / sizeof(int32_t);
213 GRN_OUTPUT_ARRAY_OPEN("errors", n);
214 for (i = 0; i < n; i++) {
215 const char *message;
216 unsigned int message_size;
217
218 message_size = grn_vector_get_element(ctx,
219 error_messages,
220 i,
221 &message,
222 NULL,
223 NULL);
224
225 GRN_OUTPUT_MAP_OPEN("error", 2);
226 GRN_OUTPUT_CSTR("return_code");
227 GRN_OUTPUT_INT64(GRN_INT32_VALUE_AT(return_codes, i));
228 GRN_OUTPUT_CSTR("message");
229 if (message_size == 0) {
230 GRN_OUTPUT_NULL();
231 } else {
232 GRN_OUTPUT_STR(message, message_size);
233 }
234 GRN_OUTPUT_MAP_CLOSE();
235 }
236 GRN_OUTPUT_ARRAY_CLOSE();
237 }
238 GRN_OUTPUT_MAP_CLOSE();
239 } else {
240 GRN_OUTPUT_INT64(ctx->impl->loader.nrecords);
241 }
242 if (ctx->impl->loader.table) {
243 grn_db_touch(ctx, DB_OBJ(ctx->impl->loader.table)->db);
244 }
245 grn_ctx_loader_clear(ctx);
246 }
247 return NULL;
248}
249
250static grn_obj *
251proc_status(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
252{
253 grn_timeval now;
254 grn_cache *cache;
255 grn_cache_statistics statistics;
256
257 grn_timeval_now(ctx, &now);
258 cache = grn_cache_current_get(ctx);
259 grn_cache_get_statistics(ctx, cache, &statistics);
260 GRN_OUTPUT_MAP_OPEN("RESULT", 10);
261 GRN_OUTPUT_CSTR("alloc_count");
262 GRN_OUTPUT_INT32(grn_alloc_count());
263 GRN_OUTPUT_CSTR("starttime");
264 GRN_OUTPUT_INT32(grn_starttime.tv_sec);
265 GRN_OUTPUT_CSTR("start_time");
266 GRN_OUTPUT_INT32(grn_starttime.tv_sec);
267 GRN_OUTPUT_CSTR("uptime");
268 GRN_OUTPUT_INT32(now.tv_sec - grn_starttime.tv_sec);
269 GRN_OUTPUT_CSTR("version");
270 GRN_OUTPUT_CSTR(grn_get_version());
271 GRN_OUTPUT_CSTR("n_queries");
272 GRN_OUTPUT_INT64(statistics.nfetches);
273 GRN_OUTPUT_CSTR("cache_hit_rate");
274 if (statistics.nfetches == 0) {
275 GRN_OUTPUT_FLOAT(0.0);
276 } else {
277 double cache_hit_rate;
278 cache_hit_rate = (double)statistics.nhits / (double)statistics.nfetches;
279 GRN_OUTPUT_FLOAT(cache_hit_rate * 100.0);
280 }
281 GRN_OUTPUT_CSTR("command_version");
282 GRN_OUTPUT_INT32(grn_ctx_get_command_version(ctx));
283 GRN_OUTPUT_CSTR("default_command_version");
284 GRN_OUTPUT_INT32(grn_get_default_command_version());
285 GRN_OUTPUT_CSTR("max_command_version");
286 GRN_OUTPUT_INT32(GRN_COMMAND_VERSION_MAX);
287 GRN_OUTPUT_MAP_CLOSE();
288
289#ifdef USE_MEMORY_DEBUG
290 grn_alloc_info_dump(&grn_gctx);
291#endif /* USE_MEMORY_DEBUG */
292
293 return NULL;
294}
295
296#define GRN_STRLEN(s) ((s) ? strlen(s) : 0)
297
298void
299grn_proc_output_object_name(grn_ctx *ctx, grn_obj *obj)
300{
301 grn_obj bulk;
302 int name_len;
303 char name[GRN_TABLE_MAX_KEY_SIZE];
304
305 if (obj) {
306 GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY);
307 name_len = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
308 GRN_TEXT_SET(ctx, &bulk, name, name_len);
309 } else {
310 GRN_VOID_INIT(&bulk);
311 }
312
313 GRN_OUTPUT_OBJ(&bulk, NULL);
314 GRN_OBJ_FIN(ctx, &bulk);
315}
316
317void
318grn_proc_output_object_id_name(grn_ctx *ctx, grn_id id)
319{
320 grn_obj *obj = NULL;
321
322 if (id != GRN_ID_NIL) {
323 obj = grn_ctx_at(ctx, id);
324 }
325
326 grn_proc_output_object_name(ctx, obj);
327}
328
329static grn_obj *
330proc_missing(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
331{
332 uint32_t plen;
333 grn_obj *outbuf = ctx->impl->output.buf;
334 static int grn_document_root_len = -1;
335 if (!grn_document_root) { return NULL; }
336 if (grn_document_root_len < 0) {
337 size_t l;
338 if ((l = strlen(grn_document_root)) > PATH_MAX) {
339 return NULL;
340 }
341 grn_document_root_len = (int)l;
342 if (l > 0 && grn_document_root[l - 1] == '/') { grn_document_root_len--; }
343 }
344 if ((plen = GRN_TEXT_LEN(VAR(0))) + grn_document_root_len < PATH_MAX) {
345 char path[PATH_MAX];
346 grn_memcpy(path, grn_document_root, grn_document_root_len);
347 path[grn_document_root_len] = '/';
348 grn_str_url_path_normalize(ctx,
349 GRN_TEXT_VALUE(VAR(0)),
350 GRN_TEXT_LEN(VAR(0)),
351 path + grn_document_root_len + 1,
352 PATH_MAX - grn_document_root_len - 1);
353 grn_bulk_put_from_file(ctx, outbuf, path);
354 } else {
355 uint32_t abbrlen = 32;
356 ERR(GRN_INVALID_ARGUMENT,
357 "too long path name: <%s/%.*s...> %u(%u)",
358 grn_document_root,
359 abbrlen < plen ? abbrlen : plen, GRN_TEXT_VALUE(VAR(0)),
360 plen + grn_document_root_len, PATH_MAX);
361 }
362 return NULL;
363}
364
365static grn_obj *
366proc_quit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
367{
368 ctx->stat = GRN_CTX_QUITTING;
369 GRN_OUTPUT_BOOL(!ctx->rc);
370 return NULL;
371}
372
373static grn_obj *
374proc_shutdown(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
375{
376 const char *mode;
377 size_t mode_size;
378
379 mode = grn_plugin_proc_get_var_string(ctx, user_data, "mode", -1, &mode_size);
380#define MODE_EQUAL(name) \
381 (mode_size == strlen(name) && memcmp(mode, name, mode_size) == 0)
382 if (mode_size == 0 || MODE_EQUAL("graceful")) {
383 /* Do nothing. This is the default. */
384 } else if (MODE_EQUAL("immediate")) {
385 grn_request_canceler_cancel_all();
386 if (ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) {
387 ctx->rc = GRN_SUCCESS;
388 }
389 } else {
390 ERR(GRN_INVALID_ARGUMENT,
391 "[shutdown] mode must be <graceful> or <immediate>: <%.*s>",
392 (int)mode_size, mode);
393 }
394#undef MODE_EQUAL
395
396 if (ctx->rc == GRN_SUCCESS) {
397 grn_gctx.stat = GRN_CTX_QUIT;
398 ctx->stat = GRN_CTX_QUITTING;
399 }
400
401 GRN_OUTPUT_BOOL(!ctx->rc);
402
403 return NULL;
404}
405
406static grn_obj *
407proc_defrag(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
408{
409 grn_obj *obj;
410 int olen, threshold;
411 olen = GRN_TEXT_LEN(VAR(0));
412
413 if (olen) {
414 obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), olen);
415 } else {
416 obj = ctx->impl->db;
417 }
418
419 threshold = GRN_TEXT_LEN(VAR(1))
420 ? grn_atoi(GRN_TEXT_VALUE(VAR(1)), GRN_BULK_CURR(VAR(1)), NULL)
421 : 0;
422
423 if (obj) {
424 grn_obj_defrag(ctx, obj, threshold);
425 } else {
426 ERR(GRN_INVALID_ARGUMENT, "defrag object not found");
427 }
428 GRN_OUTPUT_BOOL(!ctx->rc);
429 return NULL;
430}
431
432static grn_obj *
433proc_log_level(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
434{
435 grn_obj *level_name = VAR(0);
436 if (GRN_TEXT_LEN(level_name) > 0) {
437 grn_log_level max_level;
438 GRN_TEXT_PUTC(ctx, level_name, '\0');
439 if (grn_log_level_parse(GRN_TEXT_VALUE(level_name), &max_level)) {
440 grn_logger_set_max_level(ctx, max_level);
441 } else {
442 ERR(GRN_INVALID_ARGUMENT,
443 "invalid log level: <%s>", GRN_TEXT_VALUE(level_name));
444 }
445 } else {
446 ERR(GRN_INVALID_ARGUMENT, "log level is missing");
447 }
448 GRN_OUTPUT_BOOL(!ctx->rc);
449 return NULL;
450}
451
452static grn_obj *
453proc_log_put(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
454{
455 grn_obj *level_name = VAR(0);
456 grn_obj *message = VAR(1);
457 if (GRN_TEXT_LEN(level_name) > 0) {
458 grn_log_level level;
459 GRN_TEXT_PUTC(ctx, level_name, '\0');
460 if (grn_log_level_parse(GRN_TEXT_VALUE(level_name), &level)) {
461 GRN_LOG(ctx, level, "%.*s",
462 (int)GRN_TEXT_LEN(message),
463 GRN_TEXT_VALUE(message));
464 } else {
465 ERR(GRN_INVALID_ARGUMENT,
466 "invalid log level: <%s>", GRN_TEXT_VALUE(level_name));
467 }
468 } else {
469 ERR(GRN_INVALID_ARGUMENT, "log level is missing");
470 }
471 GRN_OUTPUT_BOOL(!ctx->rc);
472 return NULL;
473}
474
475static grn_obj *
476proc_log_reopen(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
477{
478 grn_log_reopen(ctx);
479 GRN_OUTPUT_BOOL(!ctx->rc);
480 return NULL;
481}
482
483static grn_rc
484proc_delete_validate_selector(grn_ctx *ctx, grn_obj *table, grn_obj *table_name,
485 grn_obj *key, grn_obj *id, grn_obj *filter)
486{
487 grn_rc rc = GRN_SUCCESS;
488
489 if (!table) {
490 rc = GRN_INVALID_ARGUMENT;
491 ERR(rc,
492 "[table][record][delete] table doesn't exist: <%.*s>",
493 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
494 return rc;
495 }
496
497 if (GRN_TEXT_LEN(key) == 0 &&
498 GRN_TEXT_LEN(id) == 0 &&
499 GRN_TEXT_LEN(filter) == 0) {
500 rc = GRN_INVALID_ARGUMENT;
501 ERR(rc,
502 "[table][record][delete] either key, id or filter must be specified: "
503 "table: <%.*s>",
504 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
505 return rc;
506 }
507
508 if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
509 rc = GRN_INVALID_ARGUMENT;
510 ERR(rc,
511 "[table][record][delete] "
512 "record selector must be one of key, id and filter: "
513 "table: <%.*s>, key: <%.*s>, id: <%.*s>, filter: <%.*s>",
514 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
515 (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
516 (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
517 (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
518 return rc;
519 }
520
521 if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter) == 0) {
522 rc = GRN_INVALID_ARGUMENT;
523 ERR(rc,
524 "[table][record][delete] "
525 "can't use both key and id: table: <%.*s>, key: <%.*s>, id: <%.*s>",
526 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
527 (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
528 (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id));
529 return rc;
530 }
531
532 if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) == 0 && GRN_TEXT_LEN(filter)) {
533 rc = GRN_INVALID_ARGUMENT;
534 ERR(rc,
535 "[table][record][delete] "
536 "can't use both key and filter: "
537 "table: <%.*s>, key: <%.*s>, filter: <%.*s>",
538 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
539 (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
540 (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
541 return rc;
542 }
543
544 if (GRN_TEXT_LEN(key) == 0 && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
545 rc = GRN_INVALID_ARGUMENT;
546 ERR(rc,
547 "[table][record][delete] "
548 "can't use both id and filter: "
549 "table: <%.*s>, id: <%.*s>, filter: <%.*s>",
550 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
551 (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
552 (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
553 return rc;
554 }
555
556 return rc;
557}
558
559static grn_obj *
560proc_delete(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
561{
562 grn_rc rc = GRN_INVALID_ARGUMENT;
563 grn_obj *table_name = VAR(0);
564 grn_obj *key = VAR(1);
565 grn_obj *id = VAR(2);
566 grn_obj *filter = VAR(3);
567 grn_obj *table = NULL;
568
569 if (GRN_TEXT_LEN(table_name) == 0) {
570 rc = GRN_INVALID_ARGUMENT;
571 ERR(rc, "[table][record][delete] table name isn't specified");
572 goto exit;
573 }
574
575 table = grn_ctx_get(ctx,
576 GRN_TEXT_VALUE(table_name),
577 GRN_TEXT_LEN(table_name));
578 rc = proc_delete_validate_selector(ctx, table, table_name, key, id, filter);
579 if (rc != GRN_SUCCESS) { goto exit; }
580
581 if (GRN_TEXT_LEN(key)) {
582 grn_obj casted_key;
583 if (key->header.domain != table->header.domain) {
584 GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain);
585 grn_obj_cast(ctx, key, &casted_key, GRN_FALSE);
586 key = &casted_key;
587 }
588 if (ctx->rc) {
589 rc = ctx->rc;
590 } else {
591 rc = grn_table_delete(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key));
592 if (key == &casted_key) {
593 GRN_OBJ_FIN(ctx, &casted_key);
594 }
595 }
596 } else if (GRN_TEXT_LEN(id)) {
597 const char *end;
598 grn_id parsed_id = grn_atoui(GRN_TEXT_VALUE(id), GRN_BULK_CURR(id), &end);
599 if (end == GRN_BULK_CURR(id)) {
600 rc = grn_table_delete_by_id(ctx, table, parsed_id);
601 } else {
602 rc = GRN_INVALID_ARGUMENT;
603 ERR(rc,
604 "[table][record][delete] id should be number: "
605 "table: <%.*s>, id: <%.*s>, detail: <%.*s|%c|%.*s>",
606 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
607 (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
608 (int)(end - GRN_TEXT_VALUE(id)), GRN_TEXT_VALUE(id),
609 end[0],
610 (int)(GRN_TEXT_VALUE(id) - end - 1), end + 1);
611 }
612 } else if (GRN_TEXT_LEN(filter)) {
613 grn_obj *cond, *v;
614
615 GRN_EXPR_CREATE_FOR_QUERY(ctx, table, cond, v);
616 grn_expr_parse(ctx, cond,
617 GRN_TEXT_VALUE(filter),
618 GRN_TEXT_LEN(filter),
619 NULL, GRN_OP_MATCH, GRN_OP_AND,
620 GRN_EXPR_SYNTAX_SCRIPT);
621 if (ctx->rc) {
622 rc = ctx->rc;
623 ERR(rc,
624 "[table][record][delete] failed to parse filter: "
625 "table: <%.*s>, filter: <%.*s>, detail: <%s>",
626 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
627 (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter),
628 ctx->errbuf);
629 } else {
630 grn_obj *records;
631
632 records = grn_table_select(ctx, table, cond, NULL, GRN_OP_OR);
633 if (records) {
634 GRN_TABLE_EACH_BEGIN(ctx, records, cursor, result_id) {
635 void *key;
636 grn_id id;
637 grn_rc sub_rc;
638
639 if (grn_table_cursor_get_key(ctx, cursor, &key) == 0) {
640 continue;
641 }
642
643 id = *(grn_id *)key;
644 sub_rc = grn_table_delete_by_id(ctx, table, id);
645 if (rc == GRN_SUCCESS) {
646 rc = sub_rc;
647 }
648 if (ctx->rc == GRN_CANCEL) {
649 break;
650 }
651 if (ctx->rc != GRN_SUCCESS) {
652 ERRCLR(ctx);
653 }
654 } GRN_TABLE_EACH_END(ctx, cursor);
655 grn_obj_unlink(ctx, records);
656 }
657 }
658 grn_obj_unlink(ctx, cond);
659 }
660
661exit :
662 if (table) {
663 grn_obj_unlink(ctx, table);
664 }
665 GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
666 return NULL;
667}
668
669grn_bool
670grn_proc_option_value_bool(grn_ctx *ctx,
671 grn_obj *option,
672 grn_bool default_value)
673{
674 const char *value;
675 size_t value_length;
676
677 if (!option) {
678 return default_value;
679 }
680
681 value = GRN_TEXT_VALUE(option);
682 value_length = GRN_TEXT_LEN(option);
683
684 if (value_length == 0) {
685 return default_value;
686 }
687
688 if (value_length == strlen("yes") &&
689 strncmp(value, "yes", value_length) == 0) {
690 return GRN_TRUE;
691 } else if (value_length == strlen("no") &&
692 strncmp(value, "no", value_length) == 0) {
693 return GRN_FALSE;
694 } else {
695 return default_value;
696 }
697}
698
699int32_t
700grn_proc_option_value_int32(grn_ctx *ctx,
701 grn_obj *option,
702 int32_t default_value)
703{
704 const char *value;
705 size_t value_length;
706 int32_t int32_value;
707 const char *rest;
708
709 if (!option) {
710 return default_value;
711 }
712
713 value = GRN_TEXT_VALUE(option);
714 value_length = GRN_TEXT_LEN(option);
715
716 if (value_length == 0) {
717 return default_value;
718 }
719
720 int32_value = grn_atoi(value, value + value_length, &rest);
721 if (rest == value + value_length) {
722 return int32_value;
723 } else {
724 return default_value;
725 }
726}
727
728const char *
729grn_proc_option_value_string(grn_ctx *ctx,
730 grn_obj *option,
731 size_t *size)
732{
733 const char *value;
734 size_t value_length;
735
736 if (!option) {
737 if (size) {
738 *size = 0;
739 }
740 return NULL;
741 }
742
743 value = GRN_TEXT_VALUE(option);
744 value_length = GRN_TEXT_LEN(option);
745
746 if (size) {
747 *size = value_length;
748 }
749
750 if (value_length == 0) {
751 return NULL;
752 } else {
753 return value;
754 }
755}
756
757grn_content_type
758grn_proc_option_value_content_type(grn_ctx *ctx,
759 grn_obj *option,
760 grn_content_type default_value)
761{
762 if (!option) {
763 return default_value;
764 }
765
766 return grn_content_type_parse(ctx, option, default_value);
767}
768
769static grn_obj *
770proc_cache_limit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
771{
772 grn_cache *cache;
773 unsigned int current_max_n_entries;
774
775 cache = grn_cache_current_get(ctx);
776 current_max_n_entries = grn_cache_get_max_n_entries(ctx, cache);
777 if (GRN_TEXT_LEN(VAR(0))) {
778 const char *rest;
779 uint32_t max = grn_atoui(GRN_TEXT_VALUE(VAR(0)),
780 GRN_BULK_CURR(VAR(0)), &rest);
781 if (GRN_BULK_CURR(VAR(0)) == rest) {
782 grn_cache_set_max_n_entries(ctx, cache, max);
783 } else {
784 ERR(GRN_INVALID_ARGUMENT,
785 "max value is invalid unsigned integer format: <%.*s>",
786 (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
787 }
788 }
789 if (ctx->rc == GRN_SUCCESS) {
790 GRN_OUTPUT_INT64(current_max_n_entries);
791 }
792 return NULL;
793}
794
795static grn_obj *
796proc_register(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
797{
798 if (GRN_TEXT_LEN(VAR(0))) {
799 const char *name;
800 GRN_TEXT_PUTC(ctx, VAR(0), '\0');
801 name = GRN_TEXT_VALUE(VAR(0));
802 grn_plugin_register(ctx, name);
803 } else {
804 ERR(GRN_INVALID_ARGUMENT, "path is required");
805 }
806 GRN_OUTPUT_BOOL(!ctx->rc);
807 return NULL;
808}
809
810void grn_ii_buffer_check(grn_ctx *ctx, grn_ii *ii, uint32_t seg);
811
812static grn_obj *
813proc_check(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
814{
815 grn_obj *obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)));
816 if (!obj) {
817 ERR(GRN_INVALID_ARGUMENT,
818 "no such object: <%.*s>", (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
819 GRN_OUTPUT_BOOL(!ctx->rc);
820 } else {
821 switch (obj->header.type) {
822 case GRN_DB :
823 GRN_OUTPUT_BOOL(!ctx->rc);
824 break;
825 case GRN_TABLE_PAT_KEY :
826 grn_pat_check(ctx, (grn_pat *)obj);
827 break;
828 case GRN_TABLE_HASH_KEY :
829 grn_hash_check(ctx, (grn_hash *)obj);
830 break;
831 case GRN_TABLE_DAT_KEY :
832 case GRN_TABLE_NO_KEY :
833 case GRN_COLUMN_FIX_SIZE :
834 GRN_OUTPUT_BOOL(!ctx->rc);
835 break;
836 case GRN_COLUMN_VAR_SIZE :
837 grn_ja_check(ctx, (grn_ja *)obj);
838 break;
839 case GRN_COLUMN_INDEX :
840 {
841 grn_ii *ii = (grn_ii *)obj;
842 struct grn_ii_header *h = ii->header;
843 char buf[8];
844 GRN_OUTPUT_ARRAY_OPEN("RESULT", 8);
845 {
846 uint32_t i, j, g =0, a = 0, b = 0;
847 uint32_t max = 0;
848 for (i = h->bgqtail; i != h->bgqhead; i = ((i + 1) & (GRN_II_BGQSIZE - 1))) {
849 j = h->bgqbody[i];
850 g++;
851 if (j > max) { max = j; }
852 }
853 for (i = 0; i < GRN_II_MAX_LSEG; i++) {
854 j = h->binfo[i];
855 if (j != GRN_II_PSEG_NOT_ASSIGNED) {
856 if (j > max) { max = j; }
857 b++;
858 }
859 }
860 for (i = 0; i < GRN_II_MAX_LSEG; i++) {
861 j = h->ainfo[i];
862 if (j != GRN_II_PSEG_NOT_ASSIGNED) {
863 if (j > max) { max = j; }
864 a++;
865 }
866 }
867 GRN_OUTPUT_MAP_OPEN("SUMMARY", 12);
868 GRN_OUTPUT_CSTR("flags");
869 grn_itoh(h->flags, buf, 8);
870 GRN_OUTPUT_STR(buf, 8);
871 GRN_OUTPUT_CSTR("max sid");
872 GRN_OUTPUT_INT64(h->smax);
873 GRN_OUTPUT_CSTR("number of garbage segments");
874 GRN_OUTPUT_INT64(g);
875 GRN_OUTPUT_CSTR("number of array segments");
876 GRN_OUTPUT_INT64(a);
877 GRN_OUTPUT_CSTR("max id of array segment");
878 GRN_OUTPUT_INT64(h->amax);
879 GRN_OUTPUT_CSTR("number of buffer segments");
880 GRN_OUTPUT_INT64(b);
881 GRN_OUTPUT_CSTR("max id of buffer segment");
882 GRN_OUTPUT_INT64(h->bmax);
883 GRN_OUTPUT_CSTR("max id of physical segment in use");
884 GRN_OUTPUT_INT64(max);
885 GRN_OUTPUT_CSTR("number of unmanaged segments");
886 GRN_OUTPUT_INT64(h->pnext - a - b - g);
887 GRN_OUTPUT_CSTR("total chunk size");
888 GRN_OUTPUT_INT64(h->total_chunk_size);
889 for (max = 0, i = 0; i < (GRN_II_MAX_CHUNK >> 3); i++) {
890 if ((j = h->chunks[i])) {
891 int k;
892 for (k = 0; k < 8; k++) {
893 if ((j & (1 << k))) { max = (i << 3) + j; }
894 }
895 }
896 }
897 GRN_OUTPUT_CSTR("max id of chunk segments in use");
898 GRN_OUTPUT_INT64(max);
899 GRN_OUTPUT_CSTR("number of garbage chunk");
900 GRN_OUTPUT_ARRAY_OPEN("NGARBAGES", GRN_II_N_CHUNK_VARIATION);
901 for (i = 0; i <= GRN_II_N_CHUNK_VARIATION; i++) {
902 GRN_OUTPUT_INT64(h->ngarbages[i]);
903 }
904 GRN_OUTPUT_ARRAY_CLOSE();
905 GRN_OUTPUT_MAP_CLOSE();
906 for (i = 0; i < GRN_II_MAX_LSEG; i++) {
907 if (h->binfo[i] < 0x20000) { grn_ii_buffer_check(ctx, ii, i); }
908 }
909 }
910 GRN_OUTPUT_ARRAY_CLOSE();
911 }
912 break;
913 }
914 }
915 return NULL;
916}
917
918static grn_obj *
919proc_truncate(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
920{
921 const char *target_name;
922 int target_name_len;
923
924 target_name_len = GRN_TEXT_LEN(VAR(0));
925 if (target_name_len > 0) {
926 target_name = GRN_TEXT_VALUE(VAR(0));
927 } else {
928 target_name_len = GRN_TEXT_LEN(VAR(1));
929 if (target_name_len == 0) {
930 ERR(GRN_INVALID_ARGUMENT, "[truncate] table name is missing");
931 goto exit;
932 }
933 target_name = GRN_TEXT_VALUE(VAR(1));
934 }
935
936 {
937 grn_obj *target = grn_ctx_get(ctx, target_name, target_name_len);
938 if (!target) {
939 ERR(GRN_INVALID_ARGUMENT,
940 "[truncate] no such target: <%.*s>", target_name_len, target_name);
941 goto exit;
942 }
943
944 switch (target->header.type) {
945 case GRN_TABLE_HASH_KEY :
946 case GRN_TABLE_PAT_KEY :
947 case GRN_TABLE_DAT_KEY :
948 case GRN_TABLE_NO_KEY :
949 grn_table_truncate(ctx, target);
950 break;
951 case GRN_COLUMN_FIX_SIZE :
952 case GRN_COLUMN_VAR_SIZE :
953 case GRN_COLUMN_INDEX :
954 grn_column_truncate(ctx, target);
955 break;
956 default:
957 {
958 grn_obj buffer;
959 GRN_TEXT_INIT(&buffer, 0);
960 grn_inspect(ctx, &buffer, target);
961 ERR(GRN_INVALID_ARGUMENT,
962 "[truncate] not a table nor column object: <%.*s>",
963 (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
964 GRN_OBJ_FIN(ctx, &buffer);
965 }
966 break;
967 }
968 }
969
970exit :
971 GRN_OUTPUT_BOOL(!ctx->rc);
972 return NULL;
973}
974
975static int
976parse_normalize_flags(grn_ctx *ctx, grn_obj *flag_names)
977{
978 int flags = 0;
979 const char *names, *names_end;
980 int length;
981
982 names = GRN_TEXT_VALUE(flag_names);
983 length = GRN_TEXT_LEN(flag_names);
984 names_end = names + length;
985 while (names < names_end) {
986 if (*names == '|' || *names == ' ') {
987 names += 1;
988 continue;
989 }
990
991#define CHECK_FLAG(name)\
992 if (((names_end - names) >= (sizeof(#name) - 1)) &&\
993 (!memcmp(names, #name, sizeof(#name) - 1))) {\
994 flags |= GRN_STRING_ ## name;\
995 names += sizeof(#name) - 1;\
996 continue;\
997 }
998
999 CHECK_FLAG(REMOVE_BLANK);
1000 CHECK_FLAG(WITH_TYPES);
1001 CHECK_FLAG(WITH_CHECKS);
1002 CHECK_FLAG(REMOVE_TOKENIZED_DELIMITER);
1003
1004#define GRN_STRING_NONE 0
1005 CHECK_FLAG(NONE);
1006#undef GRN_STRING_NONE
1007
1008 ERR(GRN_INVALID_ARGUMENT, "[normalize] invalid flag: <%.*s>",
1009 (int)(names_end - names), names);
1010 return 0;
1011#undef CHECK_FLAG
1012 }
1013
1014 return flags;
1015}
1016
1017static grn_bool
1018is_normalizer(grn_ctx *ctx, grn_obj *object)
1019{
1020 if (object->header.type != GRN_PROC) {
1021 return GRN_FALSE;
1022 }
1023
1024 if (grn_proc_get_type(ctx, object) != GRN_PROC_NORMALIZER) {
1025 return GRN_FALSE;
1026 }
1027
1028 return GRN_TRUE;
1029}
1030
1031static const char *
1032char_type_name(grn_char_type type)
1033{
1034 const char *name = "unknown";
1035
1036#define CHAR_TYPE_NAME_WITH_BLANK(type_name) do { \
1037 if (GRN_CHAR_IS_BLANK(type)) { \
1038 name = type_name "|blank"; \
1039 } else { \
1040 name = type_name; \
1041 } \
1042 } while (GRN_FALSE)
1043
1044 switch (GRN_CHAR_TYPE(type)) {
1045 case GRN_CHAR_NULL :
1046 CHAR_TYPE_NAME_WITH_BLANK("null");
1047 break;
1048 case GRN_CHAR_ALPHA :
1049 CHAR_TYPE_NAME_WITH_BLANK("alpha");
1050 break;
1051 case GRN_CHAR_DIGIT :
1052 CHAR_TYPE_NAME_WITH_BLANK("digit");
1053 break;
1054 case GRN_CHAR_SYMBOL :
1055 CHAR_TYPE_NAME_WITH_BLANK("symbol");
1056 break;
1057 case GRN_CHAR_HIRAGANA :
1058 CHAR_TYPE_NAME_WITH_BLANK("hiragana");
1059 break;
1060 case GRN_CHAR_KATAKANA :
1061 CHAR_TYPE_NAME_WITH_BLANK("katakana");
1062 break;
1063 case GRN_CHAR_KANJI :
1064 CHAR_TYPE_NAME_WITH_BLANK("kanji");
1065 break;
1066 case GRN_CHAR_OTHERS :
1067 CHAR_TYPE_NAME_WITH_BLANK("others");
1068 break;
1069 default :
1070 CHAR_TYPE_NAME_WITH_BLANK("unknown");
1071 break;
1072 }
1073
1074#undef CHAR_TYPE_NAME_WITH_BLANK
1075
1076 return name;
1077}
1078
1079static grn_obj *
1080proc_normalize(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1081{
1082 grn_obj *normalizer_name;
1083 grn_obj *string;
1084 grn_obj *flag_names;
1085
1086 normalizer_name = VAR(0);
1087 string = VAR(1);
1088 flag_names = VAR(2);
1089 if (GRN_TEXT_LEN(normalizer_name) == 0) {
1090 ERR(GRN_INVALID_ARGUMENT, "normalizer name is missing");
1091 return NULL;
1092 }
1093
1094 {
1095 grn_obj *normalizer;
1096 grn_obj *grn_string;
1097 int flags;
1098 unsigned int normalized_length_in_bytes;
1099 unsigned int normalized_n_characters;
1100
1101 flags = parse_normalize_flags(ctx, flag_names);
1102 normalizer = grn_ctx_get(ctx,
1103 GRN_TEXT_VALUE(normalizer_name),
1104 GRN_TEXT_LEN(normalizer_name));
1105 if (!normalizer) {
1106 ERR(GRN_INVALID_ARGUMENT,
1107 "[normalize] nonexistent normalizer: <%.*s>",
1108 (int)GRN_TEXT_LEN(normalizer_name),
1109 GRN_TEXT_VALUE(normalizer_name));
1110 return NULL;
1111 }
1112
1113 if (!is_normalizer(ctx, normalizer)) {
1114 grn_obj inspected;
1115 GRN_TEXT_INIT(&inspected, 0);
1116 grn_inspect(ctx, &inspected, normalizer);
1117 ERR(GRN_INVALID_ARGUMENT,
1118 "[normalize] not normalizer: %.*s",
1119 (int)GRN_TEXT_LEN(&inspected),
1120 GRN_TEXT_VALUE(&inspected));
1121 GRN_OBJ_FIN(ctx, &inspected);
1122 grn_obj_unlink(ctx, normalizer);
1123 return NULL;
1124 }
1125
1126 grn_string = grn_string_open(ctx,
1127 GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
1128 normalizer, flags);
1129 grn_obj_unlink(ctx, normalizer);
1130
1131 GRN_OUTPUT_MAP_OPEN("RESULT", 3);
1132 {
1133 const char *normalized;
1134
1135 grn_string_get_normalized(ctx, grn_string,
1136 &normalized,
1137 &normalized_length_in_bytes,
1138 &normalized_n_characters);
1139 GRN_OUTPUT_CSTR("normalized");
1140 GRN_OUTPUT_STR(normalized, normalized_length_in_bytes);
1141 }
1142 {
1143 const unsigned char *types;
1144
1145 types = grn_string_get_types(ctx, grn_string);
1146 GRN_OUTPUT_CSTR("types");
1147 if (types) {
1148 unsigned int i;
1149 GRN_OUTPUT_ARRAY_OPEN("types", normalized_n_characters);
1150 for (i = 0; i < normalized_n_characters; i++) {
1151 GRN_OUTPUT_CSTR(char_type_name(types[i]));
1152 }
1153 GRN_OUTPUT_ARRAY_CLOSE();
1154 } else {
1155 GRN_OUTPUT_ARRAY_OPEN("types", 0);
1156 GRN_OUTPUT_ARRAY_CLOSE();
1157 }
1158 }
1159 {
1160 const short *checks;
1161
1162 checks = grn_string_get_checks(ctx, grn_string);
1163 GRN_OUTPUT_CSTR("checks");
1164 if (checks) {
1165 unsigned int i;
1166 GRN_OUTPUT_ARRAY_OPEN("checks", normalized_length_in_bytes);
1167 for (i = 0; i < normalized_length_in_bytes; i++) {
1168 GRN_OUTPUT_INT32(checks[i]);
1169 }
1170 GRN_OUTPUT_ARRAY_CLOSE();
1171 } else {
1172 GRN_OUTPUT_ARRAY_OPEN("checks", 0);
1173 GRN_OUTPUT_ARRAY_CLOSE();
1174 }
1175 }
1176 GRN_OUTPUT_MAP_CLOSE();
1177
1178 grn_obj_unlink(ctx, grn_string);
1179 }
1180
1181 return NULL;
1182}
1183
1184static void
1185list_proc(grn_ctx *ctx, grn_proc_type target_proc_type,
1186 const char *name, const char *plural_name)
1187{
1188 grn_obj *db;
1189 grn_table_cursor *cursor;
1190 grn_obj target_procs;
1191
1192 db = grn_ctx_db(ctx);
1193 cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
1194 GRN_CURSOR_BY_ID);
1195 if (!cursor) {
1196 return;
1197 }
1198
1199 GRN_PTR_INIT(&target_procs, GRN_OBJ_VECTOR, GRN_ID_NIL);
1200 {
1201 grn_id id;
1202
1203 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
1204 grn_obj *obj;
1205 grn_proc_type proc_type;
1206
1207 obj = grn_ctx_at(ctx, id);
1208 if (!obj) {
1209 continue;
1210 }
1211
1212 if (obj->header.type != GRN_PROC) {
1213 grn_obj_unlink(ctx, obj);
1214 continue;
1215 }
1216
1217 proc_type = grn_proc_get_type(ctx, obj);
1218 if (proc_type != target_proc_type) {
1219 grn_obj_unlink(ctx, obj);
1220 continue;
1221 }
1222
1223 GRN_PTR_PUT(ctx, &target_procs, obj);
1224 }
1225 grn_table_cursor_close(ctx, cursor);
1226
1227 {
1228 int i, n_procs;
1229
1230 n_procs = GRN_BULK_VSIZE(&target_procs) / sizeof(grn_obj *);
1231 GRN_OUTPUT_ARRAY_OPEN(plural_name, n_procs);
1232 for (i = 0; i < n_procs; i++) {
1233 grn_obj *proc;
1234 char name[GRN_TABLE_MAX_KEY_SIZE];
1235 int name_size;
1236
1237 proc = GRN_PTR_VALUE_AT(&target_procs, i);
1238 name_size = grn_obj_name(ctx, proc, name, GRN_TABLE_MAX_KEY_SIZE);
1239 GRN_OUTPUT_MAP_OPEN(name, 1);
1240 GRN_OUTPUT_CSTR("name");
1241 GRN_OUTPUT_STR(name, name_size);
1242 GRN_OUTPUT_MAP_CLOSE();
1243
1244 grn_obj_unlink(ctx, proc);
1245 }
1246 GRN_OUTPUT_ARRAY_CLOSE();
1247 }
1248
1249 grn_obj_unlink(ctx, &target_procs);
1250 }
1251}
1252
1253static grn_obj *
1254proc_tokenizer_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1255{
1256 list_proc(ctx, GRN_PROC_TOKENIZER, "tokenizer", "tokenizers");
1257 return NULL;
1258}
1259
1260static grn_obj *
1261proc_normalizer_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1262{
1263 list_proc(ctx, GRN_PROC_NORMALIZER, "normalizer", "normalizers");
1264 return NULL;
1265}
1266
1267static grn_obj *
1268func_rand(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1269{
1270 int val;
1271 grn_obj *obj;
1272 if (nargs > 0) {
1273 int max = GRN_INT32_VALUE(args[0]);
1274 val = (int) (1.0 * max * rand() / (RAND_MAX + 1.0));
1275 } else {
1276 val = rand();
1277 }
1278 if ((obj = GRN_PROC_ALLOC(GRN_DB_INT32, 0))) {
1279 GRN_INT32_SET(ctx, obj, val);
1280 }
1281 return obj;
1282}
1283
1284static grn_obj *
1285func_now(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1286{
1287 grn_obj *obj;
1288 if ((obj = GRN_PROC_ALLOC(GRN_DB_TIME, 0))) {
1289 GRN_TIME_NOW(ctx, obj);
1290 }
1291 return obj;
1292}
1293
1294static inline grn_bool
1295is_comparable_number_type(grn_id type)
1296{
1297 return GRN_DB_INT8 <= type && type <= GRN_DB_TIME;
1298}
1299
1300static inline grn_id
1301larger_number_type(grn_id type1, grn_id type2)
1302{
1303 if (type1 == type2) {
1304 return type1;
1305 }
1306
1307 switch (type1) {
1308 case GRN_DB_FLOAT :
1309 return type1;
1310 case GRN_DB_TIME :
1311 if (type2 == GRN_DB_FLOAT) {
1312 return type2;
1313 } else {
1314 return type1;
1315 }
1316 default :
1317 if (type2 > type1) {
1318 return type2;
1319 } else {
1320 return type1;
1321 }
1322 }
1323}
1324
1325static inline grn_id
1326smaller_number_type(grn_id type1, grn_id type2)
1327{
1328 if (type1 == type2) {
1329 return type1;
1330 }
1331
1332 switch (type1) {
1333 case GRN_DB_FLOAT :
1334 return type1;
1335 case GRN_DB_TIME :
1336 if (type2 == GRN_DB_FLOAT) {
1337 return type2;
1338 } else {
1339 return type1;
1340 }
1341 default :
1342 {
1343 grn_id smaller_number_type;
1344 if (type2 > type1) {
1345 smaller_number_type = type2;
1346 } else {
1347 smaller_number_type = type1;
1348 }
1349 switch (smaller_number_type) {
1350 case GRN_DB_UINT8 :
1351 return GRN_DB_INT8;
1352 case GRN_DB_UINT16 :
1353 return GRN_DB_INT16;
1354 case GRN_DB_UINT32 :
1355 return GRN_DB_INT32;
1356 case GRN_DB_UINT64 :
1357 return GRN_DB_INT64;
1358 default :
1359 return smaller_number_type;
1360 }
1361 }
1362 }
1363}
1364
1365static inline grn_bool
1366is_negative_value(grn_obj *number)
1367{
1368 switch (number->header.domain) {
1369 case GRN_DB_INT8 :
1370 return GRN_INT8_VALUE(number) < 0;
1371 case GRN_DB_INT16 :
1372 return GRN_INT16_VALUE(number) < 0;
1373 case GRN_DB_INT32 :
1374 return GRN_INT32_VALUE(number) < 0;
1375 case GRN_DB_INT64 :
1376 return GRN_INT64_VALUE(number) < 0;
1377 case GRN_DB_TIME :
1378 return GRN_TIME_VALUE(number) < 0;
1379 case GRN_DB_FLOAT :
1380 return GRN_FLOAT_VALUE(number) < 0;
1381 default :
1382 return GRN_FALSE;
1383 }
1384}
1385
1386static inline grn_bool
1387number_safe_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, grn_id type)
1388{
1389 grn_obj_reinit(ctx, dest, type, 0);
1390 if (src->header.domain == type) {
1391 GRN_TEXT_SET(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
1392 return GRN_TRUE;
1393 }
1394
1395 switch (type) {
1396 case GRN_DB_UINT8 :
1397 if (is_negative_value(src)) {
1398 GRN_UINT8_SET(ctx, dest, 0);
1399 return GRN_TRUE;
1400 }
1401 break;
1402 case GRN_DB_UINT16 :
1403 if (is_negative_value(src)) {
1404 GRN_UINT16_SET(ctx, dest, 0);
1405 return GRN_TRUE;
1406 }
1407 break;
1408 case GRN_DB_UINT32 :
1409 if (is_negative_value(src)) {
1410 GRN_UINT32_SET(ctx, dest, 0);
1411 return GRN_TRUE;
1412 }
1413 break;
1414 case GRN_DB_UINT64 :
1415 if (is_negative_value(src)) {
1416 GRN_UINT64_SET(ctx, dest, 0);
1417 return GRN_TRUE;
1418 }
1419 break;
1420 }
1421 return grn_obj_cast(ctx, src, dest, GRN_FALSE) == GRN_SUCCESS;
1422}
1423
1424static inline int
1425compare_number(grn_ctx *ctx, grn_obj *number1, grn_obj *number2, grn_id type)
1426{
1427#define COMPARE_AND_RETURN(type, value1, value2)\
1428 {\
1429 type computed_value1 = value1;\
1430 type computed_value2 = value2;\
1431 if (computed_value1 > computed_value2) {\
1432 return 1;\
1433 } else if (computed_value1 < computed_value2) {\
1434 return -1;\
1435 } else {\
1436 return 0;\
1437 }\
1438 }
1439
1440 switch (type) {
1441 case GRN_DB_INT8 :
1442 COMPARE_AND_RETURN(int8_t,
1443 GRN_INT8_VALUE(number1),
1444 GRN_INT8_VALUE(number2));
1445 case GRN_DB_UINT8 :
1446 COMPARE_AND_RETURN(uint8_t,
1447 GRN_UINT8_VALUE(number1),
1448 GRN_UINT8_VALUE(number2));
1449 case GRN_DB_INT16 :
1450 COMPARE_AND_RETURN(int16_t,
1451 GRN_INT16_VALUE(number1),
1452 GRN_INT16_VALUE(number2));
1453 case GRN_DB_UINT16 :
1454 COMPARE_AND_RETURN(uint16_t,
1455 GRN_UINT16_VALUE(number1),
1456 GRN_UINT16_VALUE(number2));
1457 case GRN_DB_INT32 :
1458 COMPARE_AND_RETURN(int32_t,
1459 GRN_INT32_VALUE(number1),
1460 GRN_INT32_VALUE(number2));
1461 case GRN_DB_UINT32 :
1462 COMPARE_AND_RETURN(uint32_t,
1463 GRN_UINT32_VALUE(number1),
1464 GRN_UINT32_VALUE(number2));
1465 case GRN_DB_INT64 :
1466 COMPARE_AND_RETURN(int64_t,
1467 GRN_INT64_VALUE(number1),
1468 GRN_INT64_VALUE(number2));
1469 case GRN_DB_UINT64 :
1470 COMPARE_AND_RETURN(uint64_t,
1471 GRN_UINT64_VALUE(number1),
1472 GRN_UINT64_VALUE(number2));
1473 case GRN_DB_FLOAT :
1474 COMPARE_AND_RETURN(double,
1475 GRN_FLOAT_VALUE(number1),
1476 GRN_FLOAT_VALUE(number2));
1477 case GRN_DB_TIME :
1478 COMPARE_AND_RETURN(int64_t,
1479 GRN_TIME_VALUE(number1),
1480 GRN_TIME_VALUE(number2));
1481 default :
1482 return 0;
1483 }
1484
1485#undef COMPARE_AND_RETURN
1486}
1487
1488inline static void
1489get_number_in_grn_uvector(grn_ctx *ctx, grn_obj *uvector, unsigned int offset,
1490 grn_obj *buf)
1491{
1492#define GET_UVECTOR_ELEMENT_AS(type) do { \
1493 GRN_ ## type ## _SET(ctx, \
1494 buf, \
1495 GRN_ ## type ## _VALUE_AT(uvector, offset)); \
1496 } while (GRN_FALSE)
1497 switch (uvector->header.domain) {
1498 case GRN_DB_BOOL :
1499 GET_UVECTOR_ELEMENT_AS(BOOL);
1500 break;
1501 case GRN_DB_INT8 :
1502 GET_UVECTOR_ELEMENT_AS(INT8);
1503 break;
1504 case GRN_DB_UINT8 :
1505 GET_UVECTOR_ELEMENT_AS(UINT8);
1506 break;
1507 case GRN_DB_INT16 :
1508 GET_UVECTOR_ELEMENT_AS(INT16);
1509 break;
1510 case GRN_DB_UINT16 :
1511 GET_UVECTOR_ELEMENT_AS(UINT16);
1512 break;
1513 case GRN_DB_INT32 :
1514 GET_UVECTOR_ELEMENT_AS(INT32);
1515 break;
1516 case GRN_DB_UINT32 :
1517 GET_UVECTOR_ELEMENT_AS(UINT32);
1518 break;
1519 case GRN_DB_INT64 :
1520 GET_UVECTOR_ELEMENT_AS(INT64);
1521 break;
1522 case GRN_DB_UINT64 :
1523 GET_UVECTOR_ELEMENT_AS(UINT64);
1524 break;
1525 case GRN_DB_FLOAT :
1526 GET_UVECTOR_ELEMENT_AS(FLOAT);
1527 break;
1528 case GRN_DB_TIME :
1529 GET_UVECTOR_ELEMENT_AS(TIME);
1530 break;
1531 default :
1532 GET_UVECTOR_ELEMENT_AS(RECORD);
1533 break;
1534 }
1535#undef GET_UVECTOR_ELEMENT_AS
1536}
1537
1538inline static void
1539apply_max(grn_ctx *ctx, grn_obj *number, grn_obj *max,
1540 grn_obj *casted_number, grn_obj *casted_max, grn_id cast_type)
1541{
1542 grn_id domain = number->header.domain;
1543 if (!is_comparable_number_type(domain)) {
1544 return;
1545 }
1546 cast_type = larger_number_type(cast_type, domain);
1547 if (!number_safe_cast(ctx, number, casted_number, cast_type)) {
1548 return;
1549 }
1550 if (max->header.domain == GRN_DB_VOID) {
1551 grn_obj_reinit(ctx, max, cast_type, 0);
1552 GRN_TEXT_SET(ctx, max,
1553 GRN_TEXT_VALUE(casted_number),
1554 GRN_TEXT_LEN(casted_number));
1555 return;
1556 }
1557
1558 if (max->header.domain != cast_type) {
1559 if (!number_safe_cast(ctx, max, casted_max, cast_type)) {
1560 return;
1561 }
1562 grn_obj_reinit(ctx, max, cast_type, 0);
1563 GRN_TEXT_SET(ctx, max,
1564 GRN_TEXT_VALUE(casted_max),
1565 GRN_TEXT_LEN(casted_max));
1566 }
1567 if (compare_number(ctx, casted_number, max, cast_type) > 0) {
1568 grn_obj_reinit(ctx, max, cast_type, 0);
1569 GRN_TEXT_SET(ctx, max,
1570 GRN_TEXT_VALUE(casted_number),
1571 GRN_TEXT_LEN(casted_number));
1572 }
1573}
1574
1575static grn_obj *
1576func_max(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1577{
1578 grn_obj *max;
1579 grn_id cast_type = GRN_DB_INT8;
1580 grn_obj casted_max, casted_number;
1581 int i;
1582
1583 max = GRN_PROC_ALLOC(GRN_DB_VOID, 0);
1584 if (!max) {
1585 return max;
1586 }
1587
1588 GRN_VOID_INIT(&casted_max);
1589 GRN_VOID_INIT(&casted_number);
1590
1591 for (i = 0; i < nargs; i++) {
1592 switch (args[i]->header.type) {
1593 case GRN_BULK :
1594 apply_max(ctx, args[i], max, &casted_number, &casted_max, cast_type);
1595 break;
1596 case GRN_UVECTOR :
1597 {
1598 unsigned int j;
1599 unsigned int n_elements;
1600 grn_obj number_in_uvector;
1601 grn_obj *domain;
1602
1603 domain = grn_ctx_at(ctx, args[i]->header.domain);
1604 GRN_OBJ_INIT(&number_in_uvector, GRN_BULK, 0, args[i]->header.domain);
1605 n_elements = grn_uvector_size(ctx, args[i]);
1606 for (j = 0; j < n_elements; j++) {
1607 get_number_in_grn_uvector(ctx, args[i], j, &number_in_uvector);
1608 if (grn_obj_is_table(ctx, domain)) {
1609 grn_obj_reinit(ctx, &number_in_uvector, domain->header.domain, 0);
1610 grn_table_get_key2(ctx, domain,
1611 GRN_RECORD_VALUE(&number_in_uvector),
1612 &number_in_uvector);
1613 }
1614 apply_max(ctx, &number_in_uvector, max, &casted_number, &casted_max, cast_type);
1615 }
1616 GRN_OBJ_FIN(ctx, &number_in_uvector);
1617 }
1618 break;
1619 default :
1620 continue;
1621 }
1622 }
1623 GRN_OBJ_FIN(ctx, &casted_max);
1624 GRN_OBJ_FIN(ctx, &casted_number);
1625
1626 return max;
1627}
1628
1629static void
1630apply_min(grn_ctx *ctx, grn_obj *number, grn_obj *min,
1631 grn_obj *casted_number, grn_obj *casted_min, grn_id cast_type)
1632{
1633 grn_id domain = number->header.domain;
1634 if (!is_comparable_number_type(domain)) {
1635 return;
1636 }
1637 cast_type = smaller_number_type(cast_type, domain);
1638 if (!number_safe_cast(ctx, number, casted_number, cast_type)) {
1639 return;
1640 }
1641 if (min->header.domain == GRN_DB_VOID) {
1642 grn_obj_reinit(ctx, min, cast_type, 0);
1643 GRN_TEXT_SET(ctx, min,
1644 GRN_TEXT_VALUE(casted_number),
1645 GRN_TEXT_LEN(casted_number));
1646 return;
1647 }
1648
1649 if (min->header.domain != cast_type) {
1650 if (!number_safe_cast(ctx, min, casted_min, cast_type)) {
1651 return;
1652 }
1653 grn_obj_reinit(ctx, min, cast_type, 0);
1654 GRN_TEXT_SET(ctx, min,
1655 GRN_TEXT_VALUE(casted_min),
1656 GRN_TEXT_LEN(casted_min));
1657 }
1658 if (compare_number(ctx, casted_number, min, cast_type) < 0) {
1659 grn_obj_reinit(ctx, min, cast_type, 0);
1660 GRN_TEXT_SET(ctx, min,
1661 GRN_TEXT_VALUE(casted_number),
1662 GRN_TEXT_LEN(casted_number));
1663 }
1664}
1665
1666static grn_obj *
1667func_min(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1668{
1669 grn_obj *min;
1670 grn_id cast_type = GRN_DB_INT8;
1671 grn_obj casted_min, casted_number;
1672 int i;
1673
1674 min = GRN_PROC_ALLOC(GRN_DB_VOID, 0);
1675 if (!min) {
1676 return min;
1677 }
1678
1679 GRN_VOID_INIT(&casted_min);
1680 GRN_VOID_INIT(&casted_number);
1681 for (i = 0; i < nargs; i++) {
1682 switch (args[i]->header.type) {
1683 case GRN_BULK :
1684 apply_min(ctx, args[i], min, &casted_number, &casted_min, cast_type);
1685 break;
1686 case GRN_UVECTOR :
1687 {
1688 unsigned int j;
1689 unsigned int n_elements;
1690 grn_obj number_in_uvector;
1691 grn_obj *domain;
1692
1693 domain = grn_ctx_at(ctx, args[i]->header.domain);
1694 GRN_OBJ_INIT(&number_in_uvector, GRN_BULK, 0, args[i]->header.domain);
1695 n_elements = grn_uvector_size(ctx, args[i]);
1696 for (j = 0; j < n_elements; j++) {
1697 get_number_in_grn_uvector(ctx, args[i], j, &number_in_uvector);
1698 if (grn_obj_is_table(ctx, domain)) {
1699 grn_obj_reinit(ctx, &number_in_uvector, domain->header.domain, 0);
1700 grn_table_get_key2(ctx, domain,
1701 GRN_RECORD_VALUE(&number_in_uvector),
1702 &number_in_uvector);
1703 }
1704 apply_min(ctx, &number_in_uvector, min, &casted_number, &casted_min, cast_type);
1705 }
1706 GRN_OBJ_FIN(ctx, &number_in_uvector);
1707 }
1708 break;
1709 default :
1710 continue;
1711 }
1712 }
1713 GRN_OBJ_FIN(ctx, &casted_min);
1714 GRN_OBJ_FIN(ctx, &casted_number);
1715
1716 return min;
1717}
1718
1719static grn_obj *
1720func_geo_in_circle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1721{
1722 grn_obj *obj;
1723 grn_bool r = GRN_FALSE;
1724 grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
1725 switch (nargs) {
1726 case 4 :
1727 if (grn_geo_resolve_approximate_type(ctx, args[3], &type) != GRN_SUCCESS) {
1728 break;
1729 }
1730 /* fallthru */
1731 case 3 :
1732 r = grn_geo_in_circle(ctx, args[0], args[1], args[2], type);
1733 break;
1734 default :
1735 break;
1736 }
1737 if ((obj = GRN_PROC_ALLOC(GRN_DB_BOOL, 0))) {
1738 GRN_BOOL_SET(ctx, obj, r);
1739 }
1740 return obj;
1741}
1742
1743static grn_obj *
1744func_geo_in_rectangle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1745{
1746 grn_obj *obj;
1747 grn_bool r = GRN_FALSE;
1748 if (nargs == 3) {
1749 r = grn_geo_in_rectangle(ctx, args[0], args[1], args[2]);
1750 }
1751 if ((obj = GRN_PROC_ALLOC(GRN_DB_BOOL, 0))) {
1752 GRN_BOOL_SET(ctx, obj, r);
1753 }
1754 return obj;
1755}
1756
1757static grn_obj *
1758func_geo_distance(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1759{
1760 grn_obj *obj;
1761 double d = 0.0;
1762 grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
1763 switch (nargs) {
1764 case 3 :
1765 if (grn_geo_resolve_approximate_type(ctx, args[2], &type) != GRN_SUCCESS) {
1766 break;
1767 }
1768 /* fallthru */
1769 case 2 :
1770 d = grn_geo_distance(ctx, args[0], args[1], type);
1771 break;
1772 default:
1773 break;
1774 }
1775 if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
1776 GRN_FLOAT_SET(ctx, obj, d);
1777 }
1778 return obj;
1779}
1780
1781/* deprecated. */
1782static grn_obj *
1783func_geo_distance2(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1784{
1785 grn_obj *obj;
1786 double d = 0;
1787 if (nargs == 2) {
1788 d = grn_geo_distance_sphere(ctx, args[0], args[1]);
1789 }
1790 if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
1791 GRN_FLOAT_SET(ctx, obj, d);
1792 }
1793 return obj;
1794}
1795
1796/* deprecated. */
1797static grn_obj *
1798func_geo_distance3(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1799{
1800 grn_obj *obj;
1801 double d = 0;
1802 if (nargs == 2) {
1803 d = grn_geo_distance_ellipsoid(ctx, args[0], args[1]);
1804 }
1805 if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
1806 GRN_FLOAT_SET(ctx, obj, d);
1807 }
1808 return obj;
1809}
1810
1811static grn_obj *
1812func_all_records(grn_ctx *ctx, int nargs, grn_obj **args,
1813 grn_user_data *user_data)
1814{
1815 grn_obj *true_value;
1816 if ((true_value = GRN_PROC_ALLOC(GRN_DB_BOOL, 0))) {
1817 GRN_BOOL_SET(ctx, true_value, GRN_TRUE);
1818 }
1819 return true_value;
1820}
1821
1822static grn_rc
1823selector_all_records(grn_ctx *ctx, grn_obj *table, grn_obj *index,
1824 int nargs, grn_obj **args,
1825 grn_obj *res, grn_operator op)
1826{
1827 grn_posting posting;
1828
1829 memset(&posting, 0, sizeof(grn_posting));
1830 GRN_TABLE_EACH(ctx, table, 0, 0, id, NULL, NULL, NULL, {
1831 posting.rid = id;
1832 grn_ii_posting_add(ctx, &posting, (grn_hash *)res, GRN_OP_OR);
1833 });
1834
1835 return ctx->rc;
1836}
1837
1838typedef struct {
1839 grn_obj *found;
1840 grn_obj *table;
1841 grn_obj *records;
1842} selector_to_function_data;
1843
1844static grn_bool
1845selector_to_function_data_init(grn_ctx *ctx,
1846 selector_to_function_data *data,
1847 grn_user_data *user_data)
1848{
1849 grn_obj *condition = NULL;
1850 grn_obj *variable;
1851
1852 data->table = NULL;
1853 data->records = NULL;
1854
1855 data->found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
1856 if (!data->found) {
1857 return GRN_FALSE;
1858 }
1859 GRN_BOOL_SET(ctx, data->found, GRN_FALSE);
1860
1861 grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
1862 if (!condition) {
1863 return GRN_FALSE;
1864 }
1865
1866 variable = grn_expr_get_var_by_offset(ctx, condition, 0);
1867 if (!variable) {
1868 return GRN_FALSE;
1869 }
1870
1871 data->table = grn_ctx_at(ctx, variable->header.domain);
1872 if (!data->table) {
1873 return GRN_FALSE;
1874 }
1875
1876 data->records = grn_table_create(ctx, NULL, 0, NULL,
1877 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
1878 data->table, NULL);
1879 if (!data->records) {
1880 return GRN_FALSE;
1881 }
1882
1883 {
1884 grn_rset_posinfo pi;
1885 unsigned int key_size;
1886 memset(&pi, 0, sizeof(grn_rset_posinfo));
1887 pi.rid = GRN_RECORD_VALUE(variable);
1888 key_size = ((grn_hash *)(data->records))->key_size;
1889 if (grn_table_add(ctx, data->records, &pi, key_size, NULL) == GRN_ID_NIL) {
1890 return GRN_FALSE;
1891 }
1892 }
1893
1894 return GRN_TRUE;
1895}
1896
1897static void
1898selector_to_function_data_selected(grn_ctx *ctx,
1899 selector_to_function_data *data)
1900{
1901 GRN_BOOL_SET(ctx, data->found, grn_table_size(ctx, data->records) > 0);
1902}
1903
1904static void
1905selector_to_function_data_fin(grn_ctx *ctx,
1906 selector_to_function_data *data)
1907{
1908 if (data->records) {
1909 grn_obj_unlink(ctx, data->records);
1910 }
1911}
1912
1913grn_operator
1914grn_proc_option_value_mode(grn_ctx *ctx,
1915 grn_obj *option,
1916 grn_operator default_mode,
1917 const char *context)
1918{
1919 if (option->header.domain != GRN_DB_TEXT) {
1920 grn_obj inspected;
1921 GRN_TEXT_INIT(&inspected, 0);
1922 grn_inspect(ctx, &inspected, option);
1923 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
1924 "%s: mode must be text: <%.*s>",
1925 context,
1926 (int)GRN_TEXT_LEN(&inspected),
1927 GRN_TEXT_VALUE(&inspected));
1928 GRN_OBJ_FIN(ctx, &inspected);
1929 return GRN_OP_NOP;
1930 }
1931
1932 if (GRN_TEXT_LEN(option) == 0) {
1933 return default_mode;
1934 }
1935
1936#define EQUAL_MODE(name) \
1937 (GRN_TEXT_LEN(option) == strlen(name) && \
1938 memcmp(GRN_TEXT_VALUE(option), name, strlen(name)) == 0)
1939
1940 if (EQUAL_MODE("==") || EQUAL_MODE("EQUAL")) {
1941 return GRN_OP_EQUAL;
1942 } else if (EQUAL_MODE("!=") || EQUAL_MODE("NOT_EQUAL")) {
1943 return GRN_OP_NOT_EQUAL;
1944 } else if (EQUAL_MODE("<") || EQUAL_MODE("LESS")) {
1945 return GRN_OP_LESS;
1946 } else if (EQUAL_MODE(">") || EQUAL_MODE("GREATER")) {
1947 return GRN_OP_GREATER;
1948 } else if (EQUAL_MODE("<=") || EQUAL_MODE("LESS_EQUAL")) {
1949 return GRN_OP_LESS_EQUAL;
1950 } else if (EQUAL_MODE(">=") || EQUAL_MODE("GREATER_EQUAL")) {
1951 return GRN_OP_GREATER_EQUAL;
1952 } else if (EQUAL_MODE("@") || EQUAL_MODE("MATCH")) {
1953 return GRN_OP_MATCH;
1954 } else if (EQUAL_MODE("*N") || EQUAL_MODE("NEAR")) {
1955 return GRN_OP_NEAR;
1956 } else if (EQUAL_MODE("*S") || EQUAL_MODE("SIMILAR")) {
1957 return GRN_OP_SIMILAR;
1958 } else if (EQUAL_MODE("^") || EQUAL_MODE("@^") || EQUAL_MODE("PREFIX")) {
1959 return GRN_OP_PREFIX;
1960 } else if (EQUAL_MODE("$") || EQUAL_MODE("@$") || EQUAL_MODE("SUFFIX")) {
1961 return GRN_OP_SUFFIX;
1962 } else if (EQUAL_MODE("~") || EQUAL_MODE("@~") || EQUAL_MODE("REGEXP")) {
1963 return GRN_OP_REGEXP;
1964 } else {
1965 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
1966 "%s: mode must be one of them: "
1967 "["
1968 "\"==\", \"EQUAL\", "
1969 "\"!=\", \"NOT_EQUAL\", "
1970 "\"<\", \"LESS\", "
1971 "\">\", \"GREATER\", "
1972 "\"<=\", \"LESS_EQUAL\", "
1973 "\">=\", \"GREATER_EQUAL\", "
1974 "\"@\", \"MATCH\", "
1975 "\"*N\", \"NEAR\", "
1976 "\"*S\", \"SIMILAR\", "
1977 "\"^\", \"@^\", \"PREFIX\", "
1978 "\"$\", \"@$\", \"SUFFIX\", "
1979 "\"~\", \"@~\", \"REGEXP\""
1980 "]: <%.*s>",
1981 context,
1982 (int)GRN_TEXT_LEN(option),
1983 GRN_TEXT_VALUE(option));
1984 return GRN_OP_NOP;
1985 }
1986
1987#undef EQUAL_MODE
1988}
1989
1990static grn_rc
1991run_query(grn_ctx *ctx, grn_obj *table,
1992 int nargs, grn_obj **args,
1993 grn_obj *res, grn_operator op)
1994{
1995 grn_rc rc = GRN_SUCCESS;
1996 grn_obj *match_columns_string;
1997 grn_obj *query;
1998 grn_obj *query_expander_name = NULL;
1999 grn_operator default_mode = GRN_OP_MATCH;
2000 grn_expr_flags flags = GRN_EXPR_SYNTAX_QUERY;
2001 grn_bool flags_specified = GRN_FALSE;
2002 grn_obj *match_columns = NULL;
2003 grn_obj *condition = NULL;
2004 grn_obj *dummy_variable;
2005
2006 if (!(2 <= nargs && nargs <= 3)) {
2007 ERR(GRN_INVALID_ARGUMENT,
2008 "query(): wrong number of arguments (%d for 2..3)", nargs);
2009 rc = ctx->rc;
2010 goto exit;
2011 }
2012
2013 match_columns_string = args[0];
2014 query = args[1];
2015 if (nargs > 2) {
2016 grn_obj *options = args[2];
2017
2018 switch (options->header.type) {
2019 case GRN_BULK :
2020 query_expander_name = options;
2021 break;
2022 case GRN_TABLE_HASH_KEY :
2023 {
2024 grn_hash_cursor *cursor;
2025 void *key;
2026 grn_obj *value;
2027 int key_size;
2028 cursor = grn_hash_cursor_open(ctx, (grn_hash *)options,
2029 NULL, 0, NULL, 0,
2030 0, -1, 0);
2031 if (!cursor) {
2032 GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
2033 "query(): failed to open cursor for options");
2034 rc = ctx->rc;
2035 goto exit;
2036 }
2037 while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
2038 grn_hash_cursor_get_key_value(ctx, cursor, &key, &key_size,
2039 (void **)&value);
2040
2041#define KEY_EQUAL(name) \
2042 (key_size == strlen(name) && memcmp(key, name, strlen(name)) == 0)
2043 if (KEY_EQUAL("expander")) {
2044 query_expander_name = value;
2045 } else if (KEY_EQUAL("default_mode")) {
2046 default_mode = grn_proc_option_value_mode(ctx,
2047 value,
2048 GRN_OP_MATCH,
2049 "query()");
2050 if (ctx->rc != GRN_SUCCESS) {
2051 grn_hash_cursor_close(ctx, cursor);
2052 rc = ctx->rc;
2053 goto exit;
2054 }
2055 } else if (KEY_EQUAL("flags")) {
2056 flags_specified = GRN_TRUE;
2057 flags |= grn_proc_expr_query_flags_parse(ctx,
2058 GRN_TEXT_VALUE(value),
2059 GRN_TEXT_LEN(value),
2060 "query()");
2061 if (ctx->rc != GRN_SUCCESS) {
2062 grn_hash_cursor_close(ctx, cursor);
2063 rc = ctx->rc;
2064 goto exit;
2065 }
2066 } else {
2067 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
2068 "query(): unknown option name: <%.*s>",
2069 key_size, (char *)key);
2070 grn_hash_cursor_close(ctx, cursor);
2071 rc = ctx->rc;
2072 goto exit;
2073 }
2074#undef KEY_EQUAL
2075 }
2076 grn_hash_cursor_close(ctx, cursor);
2077 }
2078 break;
2079 default :
2080 {
2081 grn_obj inspected;
2082 GRN_TEXT_INIT(&inspected, 0);
2083 grn_inspect(ctx, &inspected, options);
2084 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
2085 "query(): "
2086 "3rd argument must be string or object literal: <%.*s>",
2087 (int)GRN_TEXT_LEN(&inspected),
2088 GRN_TEXT_VALUE(&inspected));
2089 GRN_OBJ_FIN(ctx, &inspected);
2090 }
2091 rc = ctx->rc;
2092 goto exit;
2093 }
2094 }
2095
2096 if (!flags_specified) {
2097 flags |= GRN_EXPR_ALLOW_PRAGMA | GRN_EXPR_ALLOW_COLUMN;
2098 }
2099
2100 if (match_columns_string->header.domain == GRN_DB_TEXT &&
2101 GRN_TEXT_LEN(match_columns_string) > 0) {
2102 GRN_EXPR_CREATE_FOR_QUERY(ctx, table, match_columns, dummy_variable);
2103 if (!match_columns) {
2104 rc = ctx->rc;
2105 goto exit;
2106 }
2107
2108 grn_expr_parse(ctx, match_columns,
2109 GRN_TEXT_VALUE(match_columns_string),
2110 GRN_TEXT_LEN(match_columns_string),
2111 NULL, GRN_OP_MATCH, GRN_OP_AND,
2112 GRN_EXPR_SYNTAX_SCRIPT);
2113 if (ctx->rc != GRN_SUCCESS) {
2114 rc = ctx->rc;
2115 goto exit;
2116 }
2117 }
2118
2119 if (query->header.domain == GRN_DB_TEXT && GRN_TEXT_LEN(query) > 0) {
2120 const char *query_string;
2121 unsigned int query_string_len;
2122 grn_obj expanded_query;
2123
2124 GRN_EXPR_CREATE_FOR_QUERY(ctx, table, condition, dummy_variable);
2125 if (!condition) {
2126 rc = ctx->rc;
2127 goto exit;
2128 }
2129
2130 query_string = GRN_TEXT_VALUE(query);
2131 query_string_len = GRN_TEXT_LEN(query);
2132
2133 GRN_TEXT_INIT(&expanded_query, 0);
2134 if (query_expander_name &&
2135 query_expander_name->header.domain == GRN_DB_TEXT &&
2136 GRN_TEXT_LEN(query_expander_name) > 0) {
2137 rc = grn_proc_syntax_expand_query(ctx,
2138 query_string, query_string_len,
2139 flags,
2140 GRN_TEXT_VALUE(query_expander_name),
2141 GRN_TEXT_LEN(query_expander_name),
2142 NULL, 0,
2143 NULL, 0,
2144 &expanded_query,
2145 "[query]");
2146 if (rc != GRN_SUCCESS) {
2147 GRN_OBJ_FIN(ctx, &expanded_query);
2148 goto exit;
2149 }
2150 query_string = GRN_TEXT_VALUE(&expanded_query);
2151 query_string_len = GRN_TEXT_LEN(&expanded_query);
2152 }
2153 grn_expr_parse(ctx, condition,
2154 query_string,
2155 query_string_len,
2156 match_columns, default_mode, GRN_OP_AND, flags);
2157 rc = ctx->rc;
2158 GRN_OBJ_FIN(ctx, &expanded_query);
2159 if (rc != GRN_SUCCESS) {
2160 goto exit;
2161 }
2162 grn_table_select(ctx, table, condition, res, op);
2163 rc = ctx->rc;
2164 }
2165
2166exit :
2167 if (match_columns) {
2168 grn_obj_unlink(ctx, match_columns);
2169 }
2170 if (condition) {
2171 grn_obj_unlink(ctx, condition);
2172 }
2173
2174 return rc;
2175}
2176
2177static grn_obj *
2178func_query(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2179{
2180 selector_to_function_data data;
2181
2182 if (selector_to_function_data_init(ctx, &data, user_data)) {
2183 grn_rc rc;
2184 rc = run_query(ctx, data.table, nargs, args, data.records, GRN_OP_AND);
2185 if (rc == GRN_SUCCESS) {
2186 selector_to_function_data_selected(ctx, &data);
2187 }
2188 }
2189 selector_to_function_data_fin(ctx, &data);
2190
2191 return data.found;
2192}
2193
2194static grn_rc
2195selector_query(grn_ctx *ctx, grn_obj *table, grn_obj *index,
2196 int nargs, grn_obj **args,
2197 grn_obj *res, grn_operator op)
2198{
2199 return run_query(ctx, table, nargs - 1, args + 1, res, op);
2200}
2201
2202static grn_rc
2203run_sub_filter(grn_ctx *ctx, grn_obj *table,
2204 int nargs, grn_obj **args,
2205 grn_obj *res, grn_operator op)
2206{
2207 grn_rc rc = GRN_SUCCESS;
2208 grn_obj *scope;
2209 grn_obj *sub_filter_string;
2210 grn_obj *scope_domain = NULL;
2211 grn_obj *sub_filter = NULL;
2212 grn_obj *dummy_variable = NULL;
2213
2214 if (nargs != 2) {
2215 ERR(GRN_INVALID_ARGUMENT,
2216 "sub_filter(): wrong number of arguments (%d for 2)", nargs);
2217 rc = ctx->rc;
2218 goto exit;
2219 }
2220
2221 scope = args[0];
2222 sub_filter_string = args[1];
2223
2224 switch (scope->header.type) {
2225 case GRN_ACCESSOR :
2226 case GRN_COLUMN_FIX_SIZE :
2227 case GRN_COLUMN_VAR_SIZE :
2228 case GRN_COLUMN_INDEX :
2229 break;
2230 default :
2231 /* TODO: put inspected the 1st argument to message */
2232 ERR(GRN_INVALID_ARGUMENT,
2233 "sub_filter(): the 1st argument must be column or accessor");
2234 rc = ctx->rc;
2235 goto exit;
2236 break;
2237 }
2238
2239 scope_domain = grn_ctx_at(ctx, grn_obj_get_range(ctx, scope));
2240
2241 if (sub_filter_string->header.domain != GRN_DB_TEXT) {
2242 /* TODO: put inspected the 2nd argument to message */
2243 ERR(GRN_INVALID_ARGUMENT,
2244 "sub_filter(): the 2nd argument must be String");
2245 rc = ctx->rc;
2246 goto exit;
2247 }
2248 if (GRN_TEXT_LEN(sub_filter_string) == 0) {
2249 ERR(GRN_INVALID_ARGUMENT,
2250 "sub_filter(): the 2nd argument must not be empty String");
2251 rc = ctx->rc;
2252 goto exit;
2253 }
2254
2255 GRN_EXPR_CREATE_FOR_QUERY(ctx, scope_domain, sub_filter, dummy_variable);
2256 if (!sub_filter) {
2257 rc = ctx->rc;
2258 goto exit;
2259 }
2260
2261 grn_expr_parse(ctx, sub_filter,
2262 GRN_TEXT_VALUE(sub_filter_string),
2263 GRN_TEXT_LEN(sub_filter_string),
2264 NULL, GRN_OP_MATCH, GRN_OP_AND,
2265 GRN_EXPR_SYNTAX_SCRIPT);
2266 if (ctx->rc != GRN_SUCCESS) {
2267 rc = ctx->rc;
2268 goto exit;
2269 }
2270
2271 {
2272 grn_obj *base_res = NULL;
2273
2274 base_res = grn_table_create(ctx, NULL, 0, NULL,
2275 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
2276 scope_domain, NULL);
2277 grn_table_select(ctx, scope_domain, sub_filter, base_res, GRN_OP_OR);
2278 if (scope->header.type == GRN_ACCESSOR) {
2279 rc = grn_accessor_resolve(ctx, scope, -1, base_res, res, op);
2280 } else {
2281 grn_accessor accessor;
2282 accessor.header.type = GRN_ACCESSOR;
2283 accessor.obj = scope;
2284 accessor.action = GRN_ACCESSOR_GET_COLUMN_VALUE;
2285 accessor.next = NULL;
2286 rc = grn_accessor_resolve(ctx, (grn_obj *)&accessor, -1, base_res,
2287 res, op);
2288 }
2289 grn_obj_unlink(ctx, base_res);
2290 }
2291
2292exit :
2293 if (scope_domain) {
2294 grn_obj_unlink(ctx, scope_domain);
2295 }
2296 if (sub_filter) {
2297 grn_obj_unlink(ctx, sub_filter);
2298 }
2299
2300 return rc;
2301}
2302
2303static grn_rc
2304selector_sub_filter(grn_ctx *ctx, grn_obj *table, grn_obj *index,
2305 int nargs, grn_obj **args,
2306 grn_obj *res, grn_operator op)
2307{
2308 return run_sub_filter(ctx, table, nargs - 1, args + 1, res, op);
2309}
2310
2311static grn_obj *
2312func_html_untag(grn_ctx *ctx, int nargs, grn_obj **args,
2313 grn_user_data *user_data)
2314{
2315 grn_obj *html_arg;
2316 int html_arg_domain;
2317 grn_obj html;
2318 grn_obj *text;
2319 const char *html_raw;
2320 int i, length;
2321 grn_bool in_tag = GRN_FALSE;
2322
2323 if (nargs != 1) {
2324 ERR(GRN_INVALID_ARGUMENT, "HTML is missing");
2325 return NULL;
2326 }
2327
2328 html_arg = args[0];
2329 html_arg_domain = html_arg->header.domain;
2330 switch (html_arg_domain) {
2331 case GRN_DB_SHORT_TEXT :
2332 case GRN_DB_TEXT :
2333 case GRN_DB_LONG_TEXT :
2334 GRN_VALUE_VAR_SIZE_INIT(&html, GRN_OBJ_DO_SHALLOW_COPY, html_arg_domain);
2335 GRN_TEXT_SET(ctx, &html, GRN_TEXT_VALUE(html_arg), GRN_TEXT_LEN(html_arg));
2336 break;
2337 default :
2338 GRN_TEXT_INIT(&html, 0);
2339 if (grn_obj_cast(ctx, html_arg, &html, GRN_FALSE)) {
2340 grn_obj inspected;
2341 GRN_TEXT_INIT(&inspected, 0);
2342 grn_inspect(ctx, &inspected, html_arg);
2343 ERR(GRN_INVALID_ARGUMENT, "failed to cast to text: <%.*s>",
2344 (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
2345 GRN_OBJ_FIN(ctx, &inspected);
2346 GRN_OBJ_FIN(ctx, &html);
2347 return NULL;
2348 }
2349 break;
2350 }
2351
2352 text = GRN_PROC_ALLOC(html.header.domain, 0);
2353 if (!text) {
2354 GRN_OBJ_FIN(ctx, &html);
2355 return NULL;
2356 }
2357
2358 html_raw = GRN_TEXT_VALUE(&html);
2359 length = GRN_TEXT_LEN(&html);
2360 for (i = 0; i < length; i++) {
2361 switch (html_raw[i]) {
2362 case '<' :
2363 in_tag = GRN_TRUE;
2364 break;
2365 case '>' :
2366 if (in_tag) {
2367 in_tag = GRN_FALSE;
2368 } else {
2369 GRN_TEXT_PUTC(ctx, text, html_raw[i]);
2370 }
2371 break;
2372 default :
2373 if (!in_tag) {
2374 GRN_TEXT_PUTC(ctx, text, html_raw[i]);
2375 }
2376 break;
2377 }
2378 }
2379
2380 GRN_OBJ_FIN(ctx, &html);
2381
2382 return text;
2383}
2384
2385static grn_bool
2386grn_text_equal_cstr(grn_ctx *ctx, grn_obj *text, const char *cstr)
2387{
2388 int cstr_len;
2389
2390 cstr_len = strlen(cstr);
2391 return (GRN_TEXT_LEN(text) == cstr_len &&
2392 strncmp(GRN_TEXT_VALUE(text), cstr, cstr_len) == 0);
2393}
2394
2395typedef enum {
2396 BETWEEN_BORDER_INVALID,
2397 BETWEEN_BORDER_INCLUDE,
2398 BETWEEN_BORDER_EXCLUDE
2399} between_border_type;
2400
2401typedef struct {
2402 grn_obj *value;
2403 grn_obj *min;
2404 grn_obj casted_min;
2405 between_border_type min_border_type;
2406 grn_obj *max;
2407 grn_obj casted_max;
2408 between_border_type max_border_type;
2409} between_data;
2410
2411static void
2412between_data_init(grn_ctx *ctx, between_data *data)
2413{
2414 GRN_VOID_INIT(&(data->casted_min));
2415 GRN_VOID_INIT(&(data->casted_max));
2416}
2417
2418static void
2419between_data_fin(grn_ctx *ctx, between_data *data)
2420{
2421 GRN_OBJ_FIN(ctx, &(data->casted_min));
2422 GRN_OBJ_FIN(ctx, &(data->casted_max));
2423}
2424
2425static between_border_type
2426between_parse_border(grn_ctx *ctx, grn_obj *border,
2427 const char *argument_description)
2428{
2429 grn_obj inspected;
2430
2431 /* TODO: support other text types */
2432 if (border->header.domain == GRN_DB_TEXT) {
2433 if (grn_text_equal_cstr(ctx, border, "include")) {
2434 return BETWEEN_BORDER_INCLUDE;
2435 } else if (grn_text_equal_cstr(ctx, border, "exclude")) {
2436 return BETWEEN_BORDER_EXCLUDE;
2437 }
2438 }
2439
2440 GRN_TEXT_INIT(&inspected, 0);
2441 grn_inspect(ctx, &inspected, border);
2442 ERR(GRN_INVALID_ARGUMENT,
2443 "between(): %s must be \"include\" or \"exclude\": <%.*s>",
2444 argument_description,
2445 (int)GRN_TEXT_LEN(&inspected),
2446 GRN_TEXT_VALUE(&inspected));
2447 grn_obj_unlink(ctx, &inspected);
2448
2449 return BETWEEN_BORDER_INVALID;
2450}
2451
2452static grn_rc
2453between_cast(grn_ctx *ctx, grn_obj *source, grn_obj *destination, grn_id domain,
2454 const char *target_argument_name)
2455{
2456 grn_rc rc;
2457
2458 GRN_OBJ_INIT(destination, GRN_BULK, 0, domain);
2459 rc = grn_obj_cast(ctx, source, destination, GRN_FALSE);
2460 if (rc != GRN_SUCCESS) {
2461 grn_obj inspected_source;
2462 grn_obj *domain_object;
2463 char domain_name[GRN_TABLE_MAX_KEY_SIZE];
2464 int domain_name_length;
2465
2466 GRN_TEXT_INIT(&inspected_source, 0);
2467 grn_inspect(ctx, &inspected_source, source);
2468
2469 domain_object = grn_ctx_at(ctx, domain);
2470 domain_name_length =
2471 grn_obj_name(ctx, domain_object, domain_name, GRN_TABLE_MAX_KEY_SIZE);
2472
2473 ERR(rc, "between(): failed to cast %s: <%.*s> -> <%.*s>",
2474 target_argument_name,
2475 (int)GRN_TEXT_LEN(&inspected_source),
2476 GRN_TEXT_VALUE(&inspected_source),
2477 domain_name_length,
2478 domain_name);
2479
2480 grn_obj_unlink(ctx, &inspected_source);
2481 grn_obj_unlink(ctx, domain_object);
2482 }
2483
2484 return rc;
2485}
2486
2487static grn_rc
2488between_parse_args(grn_ctx *ctx, int nargs, grn_obj **args, between_data *data)
2489{
2490 grn_rc rc = GRN_SUCCESS;
2491 grn_obj *min_border;
2492 grn_obj *max_border;
2493
2494 if (nargs != 5) {
2495 ERR(GRN_INVALID_ARGUMENT,
2496 "between(): wrong number of arguments (%d for 5)", nargs);
2497 rc = ctx->rc;
2498 goto exit;
2499 }
2500
2501 data->value = args[0];
2502 data->min = args[1];
2503 min_border = args[2];
2504 data->max = args[3];
2505 max_border = args[4];
2506
2507 data->min_border_type =
2508 between_parse_border(ctx, min_border, "the 3rd argument (min_border)");
2509 if (data->min_border_type == BETWEEN_BORDER_INVALID) {
2510 rc = ctx->rc;
2511 goto exit;
2512 }
2513
2514 data->max_border_type =
2515 between_parse_border(ctx, max_border, "the 5th argument (max_border)");
2516 if (data->max_border_type == BETWEEN_BORDER_INVALID) {
2517 rc = ctx->rc;
2518 goto exit;
2519 }
2520
2521 {
2522 grn_id value_type;
2523 switch (data->value->header.type) {
2524 case GRN_BULK :
2525 value_type = data->value->header.domain;
2526 break;
2527 case GRN_COLUMN_INDEX :
2528 {
2529 grn_obj *domain_object;
2530 domain_object = grn_ctx_at(ctx, data->value->header.domain);
2531 value_type = domain_object->header.domain;
2532 }
2533 break;
2534 default :
2535 value_type = grn_obj_get_range(ctx, data->value);
2536 break;
2537 }
2538 if (value_type != data->min->header.domain) {
2539 rc = between_cast(ctx, data->min, &data->casted_min, value_type, "min");
2540 if (rc != GRN_SUCCESS) {
2541 goto exit;
2542 }
2543 data->min = &(data->casted_min);
2544 }
2545
2546 if (value_type != data->max->header.domain) {
2547 rc = between_cast(ctx, data->max, &data->casted_max, value_type, "max");
2548 if (rc != GRN_SUCCESS) {
2549 goto exit;
2550 }
2551 data->max = &(data->casted_max);
2552 }
2553 }
2554
2555exit :
2556 return rc;
2557}
2558
2559static grn_bool
2560between_create_expr(grn_ctx *ctx, grn_obj *table, between_data *data,
2561 grn_obj **expr, grn_obj **variable)
2562{
2563 GRN_EXPR_CREATE_FOR_QUERY(ctx, table, *expr, *variable);
2564 if (!*expr) {
2565 return GRN_FALSE;
2566 }
2567
2568 if (data->value->header.type == GRN_BULK) {
2569 grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_PUSH, 1);
2570 } else {
2571 grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_GET_VALUE, 1);
2572 }
2573 grn_expr_append_obj(ctx, *expr, data->min, GRN_OP_PUSH, 1);
2574 if (data->min_border_type == BETWEEN_BORDER_INCLUDE) {
2575 grn_expr_append_op(ctx, *expr, GRN_OP_GREATER_EQUAL, 2);
2576 } else {
2577 grn_expr_append_op(ctx, *expr, GRN_OP_GREATER, 2);
2578 }
2579
2580 if (data->value->header.type == GRN_BULK) {
2581 grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_PUSH, 1);
2582 } else {
2583 grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_GET_VALUE, 1);
2584 }
2585 grn_expr_append_obj(ctx, *expr, data->max, GRN_OP_PUSH, 1);
2586 if (data->max_border_type == BETWEEN_BORDER_INCLUDE) {
2587 grn_expr_append_op(ctx, *expr, GRN_OP_LESS_EQUAL, 2);
2588 } else {
2589 grn_expr_append_op(ctx, *expr, GRN_OP_LESS, 2);
2590 }
2591
2592 grn_expr_append_op(ctx, *expr, GRN_OP_AND, 2);
2593
2594 return GRN_TRUE;
2595}
2596
2597static grn_obj *
2598func_between(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2599{
2600 grn_rc rc = GRN_SUCCESS;
2601 grn_obj *found;
2602 between_data data;
2603 grn_obj *condition = NULL;
2604 grn_obj *variable;
2605 grn_obj *table = NULL;
2606 grn_obj *between_expr;
2607 grn_obj *between_variable;
2608 grn_obj *result;
2609
2610 found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
2611 if (!found) {
2612 return NULL;
2613 }
2614 GRN_BOOL_SET(ctx, found, GRN_FALSE);
2615
2616 grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
2617 if (!condition) {
2618 return found;
2619 }
2620
2621 variable = grn_expr_get_var_by_offset(ctx, condition, 0);
2622 if (!variable) {
2623 return found;
2624 }
2625
2626 between_data_init(ctx, &data);
2627 rc = between_parse_args(ctx, nargs, args, &data);
2628 if (rc != GRN_SUCCESS) {
2629 goto exit;
2630 }
2631
2632 table = grn_ctx_at(ctx, variable->header.domain);
2633 if (!table) {
2634 goto exit;
2635 }
2636 if (!between_create_expr(ctx, table, &data, &between_expr, &between_variable)) {
2637 goto exit;
2638 }
2639
2640 GRN_RECORD_SET(ctx, between_variable, GRN_RECORD_VALUE(variable));
2641 result = grn_expr_exec(ctx, between_expr, 0);
2642 if (grn_obj_is_true(ctx, result)) {
2643 GRN_BOOL_SET(ctx, found, GRN_TRUE);
2644 }
2645
2646 grn_obj_unlink(ctx, between_expr);
2647 grn_obj_unlink(ctx, table);
2648
2649exit :
2650 between_data_fin(ctx, &data);
2651 if (table) {
2652 grn_obj_unlink(ctx, table);
2653 }
2654
2655 return found;
2656}
2657
2658static grn_bool
2659selector_between_sequential_search_should_use(grn_ctx *ctx,
2660 grn_obj *table,
2661 grn_obj *index,
2662 grn_obj *index_table,
2663 between_data *data,
2664 grn_obj *res,
2665 grn_operator op,
2666 double too_many_index_match_ratio)
2667{
2668 int n_index_keys;
2669
2670 if (too_many_index_match_ratio < 0.0) {
2671 return GRN_FALSE;
2672 }
2673
2674 if (op != GRN_OP_AND) {
2675 return GRN_FALSE;
2676 }
2677
2678 if (!index) {
2679 return GRN_FALSE;
2680 }
2681
2682 if (index->header.flags & GRN_OBJ_WITH_WEIGHT) {
2683 return GRN_FALSE;
2684 }
2685
2686 if (data->value->header.type == GRN_COLUMN_INDEX) {
2687 return GRN_FALSE;
2688 }
2689
2690 n_index_keys = grn_table_size(ctx, index_table);
2691 if (n_index_keys == 0) {
2692 return GRN_FALSE;
2693 }
2694
2695 switch (index_table->header.domain) {
2696 /* TODO: */
2697 /* case GRN_DB_INT8 : */
2698 /* case GRN_DB_UINT8 : */
2699 /* case GRN_DB_INT16 : */
2700 /* case GRN_DB_UINT16 : */
2701 /* case GRN_DB_INT32 : */
2702 /* case GRN_DB_UINT32 : */
2703 /* case GRN_DB_INT64 : */
2704 /* case GRN_DB_UINT64 : */
2705 /* case GRN_DB_FLOAT : */
2706 case GRN_DB_TIME :
2707 break;
2708 default :
2709 return GRN_FALSE;
2710 }
2711
2712 {
2713 grn_table_cursor *cursor;
2714 long long int all_min;
2715 long long int all_max;
2716 cursor = grn_table_cursor_open(ctx, index_table,
2717 NULL, -1,
2718 NULL, -1,
2719 0, 1,
2720 GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING);
2721 if (!cursor) {
2722 return GRN_FALSE;
2723 }
2724 if (grn_table_cursor_next(ctx, cursor) == GRN_ID_NIL) {
2725 grn_table_cursor_close(ctx, cursor);
2726 return GRN_FALSE;
2727 }
2728 {
2729 long long int *key;
2730 grn_table_cursor_get_key(ctx, cursor, (void **)&key);
2731 all_min = *key;
2732 }
2733 grn_table_cursor_close(ctx, cursor);
2734
2735 cursor = grn_table_cursor_open(ctx, index_table,
2736 NULL, 0, NULL, 0,
2737 0, 1,
2738 GRN_CURSOR_BY_KEY | GRN_CURSOR_DESCENDING);
2739 if (!cursor) {
2740 return GRN_FALSE;
2741 }
2742 if (grn_table_cursor_next(ctx, cursor) == GRN_ID_NIL) {
2743 grn_table_cursor_close(ctx, cursor);
2744 return GRN_FALSE;
2745 }
2746 {
2747 long long int *key;
2748 grn_table_cursor_get_key(ctx, cursor, (void **)&key);
2749 all_max = *key;
2750 }
2751 grn_table_cursor_close(ctx, cursor);
2752
2753 /*
2754 * We assume the following:
2755 * * homogeneous index key distribution.
2756 * * each index key matches only 1 record.
2757 * TODO: Improve me.
2758 */
2759 {
2760 int n_existing_records;
2761 int n_indexed_records;
2762 long long int all_difference;
2763 long long int argument_difference;
2764
2765 n_existing_records = grn_table_size(ctx, res);
2766
2767 all_difference = all_max - all_min;
2768 if (all_difference <= 0) {
2769 return GRN_FALSE;
2770 }
2771 argument_difference =
2772 GRN_TIME_VALUE(data->max) - GRN_TIME_VALUE(data->min);
2773 if (argument_difference <= 0) {
2774 return GRN_FALSE;
2775 }
2776 n_indexed_records =
2777 n_index_keys * ((double)argument_difference / (double)all_difference);
2778
2779 /*
2780 * Same as:
2781 * ((n_existing_record / n_indexed_records) > too_many_index_match_ratio)
2782 */
2783 if (n_existing_records > (n_indexed_records * too_many_index_match_ratio)) {
2784 return GRN_FALSE;
2785 }
2786 }
2787 }
2788
2789 return GRN_TRUE;
2790}
2791
2792static grn_rc
2793selector_between_sequential_search(grn_ctx *ctx,
2794 grn_obj *table,
2795 between_data *data,
2796 grn_obj *res,
2797 grn_operator op)
2798{
2799 {
2800 int offset = 0;
2801 int limit = -1;
2802 int flags = 0;
2803 grn_obj *target_table;
2804 grn_obj *target_column;
2805 grn_operator_exec_func *greater;
2806 grn_operator_exec_func *less;
2807 grn_table_cursor *cursor;
2808 grn_id id;
2809 grn_obj value;
2810
2811 if (op == GRN_OP_AND) {
2812 target_table = res;
2813 } else {
2814 target_table = table;
2815 }
2816 cursor = grn_table_cursor_open(ctx, target_table,
2817 NULL, 0,
2818 NULL, 0,
2819 offset, limit, flags);
2820 if (!cursor) {
2821 return ctx->rc;
2822 }
2823
2824 if (data->value->header.type == GRN_BULK) {
2825 target_column = grn_obj_column(ctx,
2826 table,
2827 GRN_TEXT_VALUE(data->value),
2828 GRN_TEXT_LEN(data->value));
2829 } else {
2830 target_column = data->value;
2831 }
2832 if (data->min_border_type == BETWEEN_BORDER_INCLUDE) {
2833 greater = grn_operator_exec_greater_equal;
2834 } else {
2835 greater = grn_operator_exec_greater;
2836 }
2837 if (data->max_border_type == BETWEEN_BORDER_INCLUDE) {
2838 less = grn_operator_exec_less_equal;
2839 } else {
2840 less = grn_operator_exec_less;
2841 }
2842
2843 GRN_VOID_INIT(&value);
2844 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
2845 grn_id record_id;
2846
2847 if (target_table == res) {
2848 grn_id *key;
2849 grn_table_cursor_get_key(ctx, cursor, (void **)&key);
2850 record_id = *key;
2851 } else {
2852 record_id = id;
2853 }
2854
2855 GRN_BULK_REWIND(&value);
2856 grn_obj_get_value(ctx, target_column, record_id, &value);
2857 if (greater(ctx, &value, data->min) && less(ctx, &value, data->max)) {
2858 grn_posting posting;
2859 posting.rid = record_id;
2860 posting.sid = 1;
2861 posting.pos = 0;
2862 posting.weight = 0;
2863 grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
2864 }
2865 }
2866
2867 GRN_OBJ_FIN(ctx, &value);
2868
2869 if (target_column != data->value &&
2870 target_column->header.type == GRN_ACCESSOR) {
2871 grn_obj_unlink(ctx, target_column);
2872 }
2873
2874 grn_table_cursor_close(ctx, cursor);
2875
2876 grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
2877 }
2878
2879 return GRN_SUCCESS;
2880}
2881
2882static grn_rc
2883selector_between(grn_ctx *ctx,
2884 grn_obj *table,
2885 grn_obj *index,
2886 int nargs,
2887 grn_obj **args,
2888 grn_obj *res,
2889 grn_operator op)
2890{
2891 grn_rc rc = GRN_SUCCESS;
2892 int offset = 0;
2893 int limit = -1;
2894 int flags = GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_KEY;
2895 between_data data;
2896 grn_bool use_sequential_search;
2897 grn_obj *index_table = NULL;
2898 grn_table_cursor *cursor;
2899 grn_id id;
2900
2901 between_data_init(ctx, &data);
2902 rc = between_parse_args(ctx, nargs - 1, args + 1, &data);
2903 if (rc != GRN_SUCCESS) {
2904 goto exit;
2905 }
2906
2907 if (data.min_border_type == BETWEEN_BORDER_EXCLUDE) {
2908 flags |= GRN_CURSOR_GT;
2909 }
2910 if (data.max_border_type == BETWEEN_BORDER_EXCLUDE) {
2911 flags |= GRN_CURSOR_LT;
2912 }
2913
2914 if (data.value->header.type == GRN_COLUMN_INDEX) {
2915 index = data.value;
2916 }
2917
2918 if (index) {
2919 switch (index->header.type) {
2920 case GRN_TABLE_NO_KEY :
2921 case GRN_TABLE_HASH_KEY :
2922 break;
2923 case GRN_TABLE_PAT_KEY :
2924 case GRN_TABLE_DAT_KEY :
2925 index_table = index;
2926 index = NULL;
2927 break;
2928 default :
2929 index_table = grn_ctx_at(ctx, index->header.domain);
2930 break;
2931 }
2932 }
2933
2934 if (index_table) {
2935 double ratio = grn_between_too_many_index_match_ratio;
2936 use_sequential_search =
2937 selector_between_sequential_search_should_use(ctx,
2938 table,
2939 index,
2940 index_table,
2941 &data,
2942 res,
2943 op,
2944 ratio);
2945 } else {
2946 use_sequential_search = GRN_TRUE;
2947 }
2948 if (use_sequential_search) {
2949 rc = selector_between_sequential_search(ctx, table, &data, res, op);
2950 goto exit;
2951 }
2952
2953 cursor = grn_table_cursor_open(ctx, index_table,
2954 GRN_BULK_HEAD(data.min),
2955 GRN_BULK_VSIZE(data.min),
2956 GRN_BULK_HEAD(data.max),
2957 GRN_BULK_VSIZE(data.max),
2958 offset, limit, flags);
2959 if (!cursor) {
2960 rc = ctx->rc;
2961 goto exit;
2962 }
2963
2964 if (index) {
2965 while ((id = grn_table_cursor_next(ctx, cursor))) {
2966 grn_ii_at(ctx, (grn_ii *)index, id, (grn_hash *)res, op);
2967 }
2968 } else {
2969 grn_posting posting;
2970 memset(&posting, 0, sizeof(grn_posting));
2971 posting.sid = 1;
2972 posting.pos = 0;
2973 while ((id = grn_table_cursor_next(ctx, cursor))) {
2974 posting.rid = id;
2975 grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
2976 }
2977 }
2978 grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
2979 grn_table_cursor_close(ctx, cursor);
2980
2981exit :
2982 between_data_fin(ctx, &data);
2983
2984 return rc;
2985}
2986
2987static grn_obj *
2988func_in_values(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2989{
2990 grn_obj *found;
2991 grn_obj *target_value;
2992 int i;
2993
2994 found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
2995 if (!found) {
2996 return NULL;
2997 }
2998 GRN_BOOL_SET(ctx, found, GRN_FALSE);
2999
3000 if (nargs < 1) {
3001 ERR(GRN_INVALID_ARGUMENT,
3002 "in_values(): wrong number of arguments (%d for 1..)", nargs);
3003 return found;
3004 }
3005
3006 target_value = args[0];
3007 for (i = 1; i < nargs; i++) {
3008 grn_obj *value = args[i];
3009 grn_bool result;
3010
3011 result = grn_operator_exec_equal(ctx, target_value, value);
3012 if (ctx->rc) {
3013 break;
3014 }
3015
3016 if (result) {
3017 GRN_BOOL_SET(ctx, found, GRN_TRUE);
3018 break;
3019 }
3020 }
3021
3022 return found;
3023}
3024
3025static grn_bool
3026is_reference_type_column(grn_ctx *ctx, grn_obj *column)
3027{
3028 grn_bool is_reference_type;
3029 grn_obj *range;
3030
3031 range = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
3032 switch (range->header.type) {
3033 case GRN_TABLE_HASH_KEY :
3034 case GRN_TABLE_PAT_KEY :
3035 case GRN_TABLE_DAT_KEY :
3036 is_reference_type = GRN_TRUE;
3037 break;
3038 default :
3039 is_reference_type = GRN_FALSE;
3040 break;
3041 }
3042 grn_obj_unlink(ctx, range);
3043
3044 return is_reference_type;
3045}
3046
3047static grn_obj *
3048selector_in_values_find_source(grn_ctx *ctx, grn_obj *index, grn_obj *res)
3049{
3050 grn_id source_id = GRN_ID_NIL;
3051 grn_obj source_ids;
3052 unsigned int n_source_ids;
3053
3054 GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
3055 grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
3056 n_source_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
3057 if (n_source_ids == 1) {
3058 source_id = GRN_UINT32_VALUE_AT(&source_ids, 0);
3059 }
3060 GRN_OBJ_FIN(ctx, &source_ids);
3061
3062 if (source_id == GRN_ID_NIL) {
3063 return NULL;
3064 } else {
3065 return grn_ctx_at(ctx, source_id);
3066 }
3067}
3068
3069static grn_bool
3070selector_in_values_sequential_search(grn_ctx *ctx,
3071 grn_obj *table,
3072 grn_obj *index,
3073 int n_values,
3074 grn_obj **values,
3075 grn_obj *res,
3076 grn_operator op)
3077{
3078 grn_obj *source;
3079 int n_existing_records;
3080
3081 if (grn_in_values_too_many_index_match_ratio < 0.0) {
3082 return GRN_FALSE;
3083 }
3084
3085 if (op != GRN_OP_AND) {
3086 return GRN_FALSE;
3087 }
3088
3089 if (index->header.flags & GRN_OBJ_WITH_WEIGHT) {
3090 return GRN_FALSE;
3091 }
3092
3093 n_existing_records = grn_table_size(ctx, res);
3094 if (n_existing_records == 0) {
3095 return GRN_TRUE;
3096 }
3097
3098 source = selector_in_values_find_source(ctx, index, res);
3099 if (!source) {
3100 return GRN_FALSE;
3101 }
3102
3103 if (!is_reference_type_column(ctx, source)) {
3104 grn_obj_unlink(ctx, source);
3105 return GRN_FALSE;
3106 }
3107
3108 {
3109 grn_obj value_ids;
3110 int i, n_value_ids;
3111 int n_indexed_records = 0;
3112
3113 {
3114 grn_id range_id;
3115 grn_obj *range;
3116
3117 range_id = grn_obj_get_range(ctx, source);
3118 range = grn_ctx_at(ctx, range_id);
3119 if (!range) {
3120 grn_obj_unlink(ctx, source);
3121 return GRN_FALSE;
3122 }
3123
3124 GRN_RECORD_INIT(&value_ids, GRN_OBJ_VECTOR, range_id);
3125 for (i = 0; i < n_values; i++) {
3126 grn_obj *value = values[i];
3127 grn_id value_id;
3128
3129 value_id = grn_table_get(ctx, range,
3130 GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
3131 if (value_id == GRN_ID_NIL) {
3132 continue;
3133 }
3134 GRN_RECORD_PUT(ctx, &value_ids, value_id);
3135 }
3136 grn_obj_unlink(ctx, range);
3137 }
3138
3139 n_value_ids = GRN_BULK_VSIZE(&value_ids) / sizeof(grn_id);
3140 for (i = 0; i < n_value_ids; i++) {
3141 grn_id value_id = GRN_RECORD_VALUE_AT(&value_ids, i);
3142 n_indexed_records += grn_ii_estimate_size(ctx, (grn_ii *)index, value_id);
3143 }
3144
3145 /*
3146 * Same as:
3147 * ((n_existing_record / n_indexed_records) >
3148 * grn_in_values_too_many_index_match_ratio)
3149 */
3150 if (n_existing_records >
3151 (n_indexed_records * grn_in_values_too_many_index_match_ratio)) {
3152 grn_obj_unlink(ctx, &value_ids);
3153 grn_obj_unlink(ctx, source);
3154 return GRN_FALSE;
3155 }
3156
3157 {
3158 grn_obj *accessor;
3159 char local_source_name[GRN_TABLE_MAX_KEY_SIZE];
3160 int local_source_name_length;
3161
3162 local_source_name_length = grn_column_name(ctx, source,
3163 local_source_name,
3164 GRN_TABLE_MAX_KEY_SIZE);
3165 grn_obj_unlink(ctx, source);
3166 accessor = grn_obj_column(ctx, res,
3167 local_source_name,
3168 local_source_name_length);
3169 {
3170 grn_table_cursor *cursor;
3171 grn_id id;
3172 grn_obj record_value;
3173
3174 GRN_VOID_INIT(&record_value);
3175 cursor = grn_table_cursor_open(ctx, res,
3176 NULL, 0, NULL, 0,
3177 0, -1, GRN_CURSOR_ASCENDING);
3178 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
3179 grn_id *record_id;
3180 grn_table_cursor_get_key(ctx, cursor, (void **)&record_id);
3181 GRN_BULK_REWIND(&record_value);
3182 grn_obj_get_value(ctx, accessor, id, &record_value);
3183 for (i = 0; i < n_value_ids; i++) {
3184 grn_id value_id = GRN_RECORD_VALUE_AT(&value_ids, i);
3185 switch (record_value.header.type) {
3186 case GRN_BULK :
3187 if (value_id == GRN_RECORD_VALUE(&record_value)) {
3188 grn_posting posting;
3189 posting.rid = *record_id;
3190 posting.sid = 1;
3191 posting.pos = 0;
3192 posting.weight = 0;
3193 grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
3194 }
3195 break;
3196 case GRN_UVECTOR :
3197 {
3198 int j, n_elements;
3199 n_elements = GRN_BULK_VSIZE(&record_value) / sizeof(grn_id);
3200 for (j = 0; j < n_elements; j++) {
3201 if (value_id == GRN_RECORD_VALUE_AT(&record_value, j)) {
3202 grn_posting posting;
3203 posting.rid = *record_id;
3204 posting.sid = 1;
3205 posting.pos = 0;
3206 posting.weight = 0;
3207 grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
3208 }
3209 }
3210 }
3211 break;
3212 default :
3213 break;
3214 }
3215 }
3216 }
3217 grn_table_cursor_close(ctx, cursor);
3218 grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
3219 GRN_OBJ_FIN(ctx, &record_value);
3220 }
3221 grn_obj_unlink(ctx, accessor);
3222 }
3223 grn_obj_unlink(ctx, &value_ids);
3224 }
3225 grn_obj_unlink(ctx, source);
3226
3227 return GRN_TRUE;
3228}
3229
3230static grn_rc
3231selector_in_values(grn_ctx *ctx, grn_obj *table, grn_obj *index,
3232 int nargs, grn_obj **args,
3233 grn_obj *res, grn_operator op)
3234{
3235 grn_rc rc = GRN_SUCCESS;
3236 int i, n_values;
3237 grn_obj **values;
3238
3239 if (!index) {
3240 return GRN_INVALID_ARGUMENT;
3241 }
3242
3243 if (nargs < 2) {
3244 ERR(GRN_INVALID_ARGUMENT,
3245 "in_values(): wrong number of arguments (%d for 1..)", nargs);
3246 return ctx->rc;
3247 }
3248
3249 n_values = nargs - 2;
3250 values = args + 2;
3251
3252 if (n_values == 0) {
3253 return rc;
3254 }
3255
3256 if (selector_in_values_sequential_search(ctx, table, index,
3257 n_values, values,
3258 res, op)) {
3259 return ctx->rc;
3260 }
3261
3262 ctx->flags |= GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
3263 for (i = 0; i < n_values; i++) {
3264 grn_obj *value = values[i];
3265 grn_search_optarg search_options;
3266 memset(&search_options, 0, sizeof(grn_search_optarg));
3267 search_options.mode = GRN_OP_EXACT;
3268 search_options.similarity_threshold = 0;
3269 search_options.max_interval = 0;
3270 search_options.weight_vector = NULL;
3271 search_options.vector_size = 0;
3272 search_options.proc = NULL;
3273 search_options.max_size = 0;
3274 search_options.scorer = NULL;
3275 if (i == n_values - 1) {
3276 ctx->flags &= ~GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
3277 }
3278 rc = grn_obj_search(ctx, index, value, res, op, &search_options);
3279 if (rc != GRN_SUCCESS) {
3280 break;
3281 }
3282 }
3283
3284 return rc;
3285}
3286
3287static grn_obj *
3288proc_range_filter(grn_ctx *ctx, int nargs, grn_obj **args,
3289 grn_user_data *user_data)
3290{
3291 grn_obj *table_name = VAR(0);
3292 grn_obj *column_name = VAR(1);
3293 grn_obj *min = VAR(2);
3294 grn_obj *min_border = VAR(3);
3295 grn_obj *max = VAR(4);
3296 grn_obj *max_border = VAR(5);
3297 grn_obj *offset = VAR(6);
3298 grn_obj *limit = VAR(7);
3299 grn_obj *filter = VAR(8);
3300 grn_obj *output_columns = VAR(9);
3301 grn_obj *table;
3302 grn_obj *res = NULL;
3303 grn_obj *filter_expr = NULL;
3304 grn_obj *filter_variable = NULL;
3305 int real_offset;
3306 int real_limit;
3307
3308 table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_name), GRN_TEXT_LEN(table_name));
3309 if (!table) {
3310 ERR(GRN_INVALID_ARGUMENT,
3311 "[range_filter] nonexistent table <%.*s>",
3312 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
3313 return NULL;
3314 }
3315
3316 if (GRN_TEXT_LEN(filter) > 0) {
3317 GRN_EXPR_CREATE_FOR_QUERY(ctx, table, filter_expr, filter_variable);
3318 if (!filter_expr) {
3319 ERR(GRN_INVALID_ARGUMENT,
3320 "[range_filter] failed to create expression");
3321 goto exit;
3322 }
3323
3324 grn_expr_parse(ctx, filter_expr,
3325 GRN_TEXT_VALUE(filter), GRN_TEXT_LEN(filter),
3326 NULL, GRN_OP_MATCH, GRN_OP_AND, GRN_EXPR_SYNTAX_SCRIPT);
3327 if (ctx->rc != GRN_SUCCESS) {
3328 goto exit;
3329 }
3330 }
3331
3332 res = grn_table_create(ctx, NULL, 0, NULL,
3333 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3334 table, NULL);
3335 if (!res) {
3336 ERR(GRN_INVALID_ARGUMENT,
3337 "[range_filter] failed to result table");
3338 goto exit;
3339 }
3340
3341 {
3342 grn_obj int32_value;
3343
3344 GRN_INT32_INIT(&int32_value, 0);
3345
3346 if (GRN_TEXT_LEN(offset) > 0) {
3347 if (grn_obj_cast(ctx, offset, &int32_value, GRN_FALSE) != GRN_SUCCESS) {
3348 ERR(GRN_INVALID_ARGUMENT,
3349 "[range_filter] invalid offset format: <%.*s>",
3350 (int)GRN_TEXT_LEN(offset), GRN_TEXT_VALUE(offset));
3351 GRN_OBJ_FIN(ctx, &int32_value);
3352 goto exit;
3353 }
3354 real_offset = GRN_INT32_VALUE(&int32_value);
3355 } else {
3356 real_offset = 0;
3357 }
3358
3359 GRN_BULK_REWIND(&int32_value);
3360
3361 if (GRN_TEXT_LEN(limit) > 0) {
3362 if (grn_obj_cast(ctx, limit, &int32_value, GRN_FALSE) != GRN_SUCCESS) {
3363 ERR(GRN_INVALID_ARGUMENT,
3364 "[range_filter] invalid limit format: <%.*s>",
3365 (int)GRN_TEXT_LEN(limit), GRN_TEXT_VALUE(limit));
3366 GRN_OBJ_FIN(ctx, &int32_value);
3367 goto exit;
3368 }
3369 real_limit = GRN_INT32_VALUE(&int32_value);
3370 } else {
3371 real_limit = GRN_SELECT_DEFAULT_LIMIT;
3372 }
3373
3374 GRN_OBJ_FIN(ctx, &int32_value);
3375 }
3376 {
3377 grn_rc rc;
3378 int original_offset = real_offset;
3379 int original_limit = real_limit;
3380 rc = grn_normalize_offset_and_limit(ctx, grn_table_size(ctx, table),
3381 &real_offset, &real_limit);
3382 switch (rc) {
3383 case GRN_TOO_SMALL_OFFSET :
3384 ERR(GRN_INVALID_ARGUMENT,
3385 "[range_filter] too small offset: <%d>", original_offset);
3386 goto exit;
3387 case GRN_TOO_LARGE_OFFSET :
3388 ERR(GRN_INVALID_ARGUMENT,
3389 "[range_filter] too large offset: <%d>", original_offset);
3390 goto exit;
3391 case GRN_TOO_SMALL_LIMIT :
3392 ERR(GRN_INVALID_ARGUMENT,
3393 "[range_filter] too small limit: <%d>", original_limit);
3394 goto exit;
3395 default :
3396 break;
3397 }
3398 }
3399
3400 if (real_limit != 0) {
3401 grn_table_sort_key *sort_keys;
3402 unsigned int n_sort_keys;
3403 sort_keys = grn_table_sort_key_from_str(ctx,
3404 GRN_TEXT_VALUE(column_name),
3405 GRN_TEXT_LEN(column_name),
3406 table,
3407 &n_sort_keys);
3408 if (n_sort_keys == 1) {
3409 grn_table_sort_key *sort_key;
3410 grn_obj *index;
3411 int n_indexes;
3412 grn_operator op = GRN_OP_OR;
3413
3414 sort_key = &(sort_keys[0]);
3415 n_indexes = grn_column_index(ctx, sort_key->key, GRN_OP_LESS,
3416 &index, 1, NULL);
3417 if (n_indexes > 0) {
3418 grn_obj *lexicon;
3419 grn_table_cursor *table_cursor;
3420 int table_cursor_flags = 0;
3421 between_border_type min_border_type;
3422 between_border_type max_border_type;
3423 grn_obj real_min;
3424 grn_obj real_max;
3425 int n_records = 0;
3426 grn_obj *index_cursor;
3427 int index_cursor_flags = 0;
3428 grn_posting *posting;
3429
3430 lexicon = grn_ctx_at(ctx, index->header.domain);
3431 if (sort_key->flags & GRN_TABLE_SORT_DESC) {
3432 table_cursor_flags |= GRN_CURSOR_DESCENDING;
3433 } else {
3434 table_cursor_flags |= GRN_CURSOR_ASCENDING;
3435 }
3436 if (GRN_TEXT_LEN(min_border) > 0) {
3437 min_border_type = between_parse_border(ctx, min_border, "min_border");
3438 } else {
3439 min_border_type = BETWEEN_BORDER_INCLUDE;
3440 }
3441 if (GRN_TEXT_LEN(max_border) > 0) {
3442 max_border_type = between_parse_border(ctx, max_border, "max_border");
3443 } else {
3444 max_border_type = BETWEEN_BORDER_INCLUDE;
3445 }
3446 if (min_border_type == BETWEEN_BORDER_EXCLUDE) {
3447 table_cursor_flags |= GRN_CURSOR_GT;
3448 }
3449 if (max_border_type == BETWEEN_BORDER_EXCLUDE) {
3450 table_cursor_flags |= GRN_CURSOR_LT;
3451 }
3452 GRN_OBJ_INIT(&real_min, GRN_BULK, 0, lexicon->header.domain);
3453 GRN_OBJ_INIT(&real_max, GRN_BULK, 0, lexicon->header.domain);
3454 if (GRN_TEXT_LEN(min) > 0) {
3455 grn_obj_cast(ctx, min, &real_min, GRN_FALSE);
3456 }
3457 if (GRN_TEXT_LEN(max) > 0) {
3458 grn_obj_cast(ctx, max, &real_max, GRN_FALSE);
3459 }
3460 table_cursor = grn_table_cursor_open(ctx, lexicon,
3461 GRN_BULK_HEAD(&real_min),
3462 GRN_BULK_VSIZE(&real_min),
3463 GRN_BULK_HEAD(&real_max),
3464 GRN_BULK_VSIZE(&real_max),
3465 0, -1, table_cursor_flags);
3466 index_cursor = grn_index_cursor_open(ctx, table_cursor,
3467 index, GRN_ID_NIL, GRN_ID_NIL,
3468 index_cursor_flags);
3469 while ((posting = grn_index_cursor_next(ctx, index_cursor, NULL))) {
3470 grn_bool result_boolean = GRN_FALSE;
3471
3472 if (filter_expr) {
3473 grn_obj *result;
3474 GRN_RECORD_SET(ctx, filter_variable, posting->rid);
3475 result = grn_expr_exec(ctx, filter_expr, 0);
3476 if (ctx->rc) {
3477 break;
3478 }
3479 result_boolean = grn_obj_is_true(ctx, result);
3480 } else {
3481 result_boolean = GRN_TRUE;
3482 }
3483
3484 if (result_boolean) {
3485 if (n_records >= real_offset) {
3486 grn_ii_posting_add(ctx, posting, (grn_hash *)res, op);
3487 }
3488 n_records++;
3489 if (n_records == real_limit) {
3490 break;
3491 }
3492 }
3493 }
3494 grn_obj_unlink(ctx, index_cursor);
3495 grn_table_cursor_close(ctx, table_cursor);
3496
3497 GRN_OBJ_FIN(ctx, &real_min);
3498 GRN_OBJ_FIN(ctx, &real_max);
3499 }
3500 grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
3501 }
3502 grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
3503 }
3504
3505 if (ctx->rc == GRN_SUCCESS) {
3506 const char *raw_output_columns;
3507 int raw_output_columns_len;
3508
3509 raw_output_columns = GRN_TEXT_VALUE(output_columns);
3510 raw_output_columns_len = GRN_TEXT_LEN(output_columns);
3511 if (raw_output_columns_len == 0) {
3512 raw_output_columns = GRN_SELECT_DEFAULT_OUTPUT_COLUMNS;
3513 raw_output_columns_len = strlen(raw_output_columns);
3514 }
3515 grn_proc_select_output_columns(ctx, res, -1, real_offset, real_limit,
3516 raw_output_columns,
3517 raw_output_columns_len,
3518 filter_expr);
3519 }
3520
3521exit :
3522 if (filter_expr) {
3523 grn_obj_unlink(ctx, filter_expr);
3524 }
3525 if (res) {
3526 grn_obj_unlink(ctx, res);
3527 }
3528
3529 return NULL;
3530}
3531
3532static grn_obj *
3533proc_request_cancel(grn_ctx *ctx, int nargs, grn_obj **args,
3534 grn_user_data *user_data)
3535{
3536 grn_obj *id = VAR(0);
3537 grn_bool canceled;
3538
3539 if (GRN_TEXT_LEN(id) == 0) {
3540 ERR(GRN_INVALID_ARGUMENT, "[request_cancel] ID is missing");
3541 return NULL;
3542 }
3543
3544 canceled = grn_request_canceler_cancel(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id));
3545
3546 GRN_OUTPUT_MAP_OPEN("result", 2);
3547 GRN_OUTPUT_CSTR("id");
3548 GRN_OUTPUT_STR(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id));
3549 GRN_OUTPUT_CSTR("canceled");
3550 GRN_OUTPUT_BOOL(canceled);
3551 GRN_OUTPUT_MAP_CLOSE();
3552
3553 return NULL;
3554}
3555
3556static grn_obj *
3557proc_plugin_register(grn_ctx *ctx, int nargs, grn_obj **args,
3558 grn_user_data *user_data)
3559{
3560 if (GRN_TEXT_LEN(VAR(0))) {
3561 const char *name;
3562 GRN_TEXT_PUTC(ctx, VAR(0), '\0');
3563 name = GRN_TEXT_VALUE(VAR(0));
3564 grn_plugin_register(ctx, name);
3565 } else {
3566 ERR(GRN_INVALID_ARGUMENT, "[plugin_register] name is missing");
3567 }
3568 GRN_OUTPUT_BOOL(!ctx->rc);
3569 return NULL;
3570}
3571
3572static grn_obj *
3573proc_plugin_unregister(grn_ctx *ctx, int nargs, grn_obj **args,
3574 grn_user_data *user_data)
3575{
3576 if (GRN_TEXT_LEN(VAR(0))) {
3577 const char *name;
3578 GRN_TEXT_PUTC(ctx, VAR(0), '\0');
3579 name = GRN_TEXT_VALUE(VAR(0));
3580 grn_plugin_unregister(ctx, name);
3581 } else {
3582 ERR(GRN_INVALID_ARGUMENT, "[plugin_unregister] name is missing");
3583 }
3584 GRN_OUTPUT_BOOL(!ctx->rc);
3585 return NULL;
3586}
3587
3588static grn_obj *
3589proc_io_flush(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3590{
3591 grn_obj *target_name;
3592 grn_obj *recursive;
3593 grn_obj *only_opened;
3594 grn_obj *target;
3595 grn_bool is_recursive;
3596 grn_bool is_only_opened;
3597
3598 target_name = VAR(0);
3599 recursive = VAR(1);
3600 only_opened = VAR(2);
3601
3602 if (GRN_TEXT_LEN(target_name) > 0) {
3603 target = grn_ctx_get(ctx,
3604 GRN_TEXT_VALUE(target_name),
3605 GRN_TEXT_LEN(target_name));
3606 if (!target) {
3607 ERR(GRN_INVALID_ARGUMENT, "[io_flush] unknown target: <%.*s>",
3608 (int)GRN_TEXT_LEN(target_name),
3609 GRN_TEXT_VALUE(target_name));
3610 GRN_OUTPUT_BOOL(GRN_FALSE);
3611 return NULL;
3612 }
3613 } else {
3614 target = grn_ctx_db(ctx);
3615 }
3616
3617 is_recursive = grn_proc_option_value_bool(ctx, recursive, GRN_TRUE);
3618 is_only_opened = grn_proc_option_value_bool(ctx, only_opened, GRN_FALSE);
3619 {
3620 grn_rc rc;
3621 if (target->header.type == GRN_DB && is_only_opened) {
3622 rc = grn_obj_flush(ctx, target);
3623 if (rc == GRN_SUCCESS) {
3624 GRN_TABLE_EACH_BEGIN_FLAGS(ctx, target, cursor, id, GRN_CURSOR_BY_ID) {
3625 grn_obj *sub_target;
3626
3627 if (id < GRN_N_RESERVED_TYPES) {
3628 continue;
3629 }
3630
3631 if (!grn_ctx_is_opened(ctx, id)) {
3632 continue;
3633 }
3634
3635 sub_target = grn_ctx_at(ctx, id);
3636 rc = grn_obj_flush(ctx, sub_target);
3637 if (rc != GRN_SUCCESS) {
3638 break;
3639 }
3640 } GRN_TABLE_EACH_END(ctx, cursor);
3641 }
3642 } else {
3643 if (is_recursive) {
3644 rc = grn_obj_flush_recursive(ctx, target);
3645 } else {
3646 rc = grn_obj_flush(ctx, target);
3647 }
3648 }
3649 GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
3650 }
3651
3652
3653 return NULL;
3654}
3655
3656static grn_obj *
3657proc_thread_limit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3658{
3659 grn_obj *max_bulk;
3660 uint32_t current_limit;
3661
3662 current_limit = grn_thread_get_limit();
3663 GRN_OUTPUT_INT64(current_limit);
3664
3665 max_bulk = VAR(0);
3666 if (GRN_TEXT_LEN(max_bulk) > 0) {
3667 uint32_t max;
3668 const char *max_text = GRN_TEXT_VALUE(max_bulk);
3669 const char *max_text_end;
3670 const char *max_text_rest;
3671
3672 max_text_end = max_text + GRN_TEXT_LEN(max_bulk);
3673 max = grn_atoui(max_text, max_text_end, &max_text_rest);
3674 if (max_text_rest != max_text_end) {
3675 ERR(GRN_INVALID_ARGUMENT,
3676 "[thread_limit] max must be unsigned integer value: <%.*s>",
3677 (int)GRN_TEXT_LEN(max_bulk),
3678 max_text);
3679 return NULL;
3680 }
3681 if (max == 0) {
3682 ERR(GRN_INVALID_ARGUMENT,
3683 "[thread_limit] max must be 1 or larger: <%.*s>",
3684 (int)GRN_TEXT_LEN(max_bulk),
3685 max_text);
3686 return NULL;
3687 }
3688 grn_thread_set_limit(max);
3689 }
3690
3691 return NULL;
3692}
3693
3694static grn_obj *
3695proc_database_unmap(grn_ctx *ctx, int nargs, grn_obj **args,
3696 grn_user_data *user_data)
3697{
3698 grn_rc rc;
3699 uint32_t current_limit;
3700
3701 current_limit = grn_thread_get_limit();
3702 if (current_limit != 1) {
3703 ERR(GRN_OPERATION_NOT_PERMITTED,
3704 "[database_unmap] the max number of threads must be 1: <%u>",
3705 current_limit);
3706 GRN_OUTPUT_BOOL(GRN_FALSE);
3707 return NULL;
3708 }
3709
3710 rc = grn_db_unmap(ctx, grn_ctx_db(ctx));
3711 GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
3712
3713 return NULL;
3714}
3715
3716static grn_obj *
3717proc_reindex(grn_ctx *ctx, int nargs, grn_obj **args,
3718 grn_user_data *user_data)
3719{
3720 grn_obj *target_name;
3721 grn_obj *target;
3722
3723 target_name = VAR(0);
3724 if (GRN_TEXT_LEN(target_name) == 0) {
3725 target = grn_ctx_db(ctx);
3726 } else {
3727 target = grn_ctx_get(ctx,
3728 GRN_TEXT_VALUE(target_name),
3729 GRN_TEXT_LEN(target_name));
3730 if (!target) {
3731 ERR(GRN_INVALID_ARGUMENT,
3732 "[reindex] nonexistent target: <%.*s>",
3733 (int)GRN_TEXT_LEN(target_name),
3734 GRN_TEXT_VALUE(target_name));
3735 GRN_OUTPUT_BOOL(GRN_FALSE);
3736 return NULL;
3737 }
3738 }
3739
3740 grn_obj_reindex(ctx, target);
3741
3742 GRN_OUTPUT_BOOL(ctx->rc == GRN_SUCCESS);
3743
3744 return NULL;
3745}
3746
3747static grn_rc
3748selector_prefix_rk_search_key(grn_ctx *ctx,
3749 grn_obj *table,
3750 grn_obj *column,
3751 grn_obj *query,
3752 grn_obj *res,
3753 grn_operator op)
3754{
3755 grn_rc rc = GRN_SUCCESS;
3756
3757 if (!grn_obj_is_key_accessor(ctx, column)) {
3758 grn_obj inspected_column;
3759 GRN_TEXT_INIT(&inspected_column, 0);
3760 grn_inspect(ctx, &inspected_column, column);
3761 ERR(GRN_INVALID_ARGUMENT,
3762 "prefix_rk_serach(): column must be _key: %.*s",
3763 (int)GRN_TEXT_LEN(&inspected_column),
3764 GRN_TEXT_VALUE(&inspected_column));
3765 rc = ctx->rc;
3766 GRN_OBJ_FIN(ctx, &inspected_column);
3767 goto exit;
3768 }
3769
3770 if (table->header.type != GRN_TABLE_PAT_KEY) {
3771 grn_obj inspected_table;
3772 GRN_TEXT_INIT(&inspected_table, 0);
3773 grn_inspect(ctx, &inspected_table, table);
3774 ERR(GRN_INVALID_ARGUMENT,
3775 "prefix_rk_serach(): table of _key must TABLE_PAT_KEY: %.*s",
3776 (int)GRN_TEXT_LEN(&inspected_table),
3777 GRN_TEXT_VALUE(&inspected_table));
3778 rc = ctx->rc;
3779 GRN_OBJ_FIN(ctx, &inspected_table);
3780 goto exit;
3781 }
3782
3783 GRN_TABLE_EACH_BEGIN_MIN(ctx,
3784 table,
3785 cursor,
3786 id,
3787 GRN_TEXT_VALUE(query),
3788 GRN_TEXT_LEN(query),
3789 GRN_CURSOR_PREFIX | GRN_CURSOR_RK) {
3790 grn_posting posting;
3791 posting.rid = id;
3792 posting.sid = 1;
3793 posting.pos = 0;
3794 posting.weight = 0;
3795 grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
3796 } GRN_TABLE_EACH_END(ctx, cursor);
3797 grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
3798
3799exit :
3800 return rc;
3801}
3802
3803static grn_rc
3804selector_prefix_rk_search_index(grn_ctx *ctx,
3805 grn_obj *index,
3806 grn_obj *query,
3807 grn_obj *res,
3808 grn_operator op)
3809{
3810 grn_rc rc = GRN_SUCCESS;
3811 grn_obj *table;
3812
3813 table = grn_column_table(ctx, index);
3814
3815 GRN_TABLE_EACH_BEGIN_MIN(ctx,
3816 table,
3817 cursor,
3818 id,
3819 GRN_TEXT_VALUE(query),
3820 GRN_TEXT_LEN(query),
3821 GRN_CURSOR_PREFIX | GRN_CURSOR_RK) {
3822 grn_ii_at(ctx, (grn_ii *)index, id, (grn_hash *)res, op);
3823 } GRN_TABLE_EACH_END(ctx, cursor);
3824 grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
3825
3826 return rc;
3827}
3828
3829static grn_rc
3830selector_prefix_rk_search(grn_ctx *ctx,
3831 grn_obj *table,
3832 grn_obj *index,
3833 int nargs,
3834 grn_obj **args,
3835 grn_obj *res,
3836 grn_operator op)
3837{
3838 grn_rc rc = GRN_SUCCESS;
3839 grn_obj *column;
3840 grn_obj *query;
3841
3842 if ((nargs - 1) != 2) {
3843 ERR(GRN_INVALID_ARGUMENT,
3844 "prefix_rk_serach(): wrong number of arguments (%d for 2)", nargs - 1);
3845 return ctx->rc;
3846 }
3847
3848 column = args[1];
3849 query = args[2];
3850
3851 if (index) {
3852 rc = selector_prefix_rk_search_index(ctx, index, query, res, op);
3853 } else if (grn_obj_is_accessor(ctx, column) &&
3854 ((grn_accessor *)column)->next) {
3855 grn_obj *accessor = column;
3856 unsigned int accessor_deep = 0;
3857 grn_obj *base_table = NULL;
3858 grn_obj *base_column = NULL;
3859 grn_obj *base_index = NULL;
3860 grn_obj *base_res = NULL;
3861 grn_accessor *a;
3862
3863 for (a = (grn_accessor *)accessor; a; a = a->next) {
3864 if (a->next) {
3865 accessor_deep++;
3866 } else {
3867 if (grn_obj_is_data_column(ctx, a->obj)) {
3868 grn_operator selector_op;
3869 grn_index_datum index_data;
3870 unsigned int n_index_datum;
3871
3872 selector_op = grn_proc_get_selector_operator(ctx, args[0]);
3873 base_column = a->obj;
3874 base_table = grn_column_table(ctx, a->obj);
3875 n_index_datum = grn_column_find_index_data(ctx,
3876 base_column,
3877 selector_op,
3878 &index_data,
3879 1);
3880 if (n_index_datum > 0) {
3881 base_index = index_data.index;
3882 }
3883 } else {
3884 base_column = (grn_obj *)a;
3885 base_table = a->obj;
3886 }
3887 base_res = grn_table_create(ctx, NULL, 0, NULL,
3888 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3889 base_table, NULL);
3890 }
3891 }
3892 if (base_index) {
3893 rc = selector_prefix_rk_search_index(ctx,
3894 base_index,
3895 query,
3896 base_res,
3897 GRN_OP_OR);
3898 } else {
3899 rc = selector_prefix_rk_search_key(ctx,
3900 base_table,
3901 base_column,
3902 query,
3903 base_res,
3904 GRN_OP_OR);
3905 }
3906 if (rc == GRN_SUCCESS) {
3907 grn_accessor_resolve(ctx,
3908 accessor,
3909 accessor_deep,
3910 base_res,
3911 res,
3912 op);
3913 }
3914 grn_obj_close(ctx, base_res);
3915 } else {
3916 rc = selector_prefix_rk_search_key(ctx,
3917 table,
3918 column,
3919 query,
3920 res,
3921 op);
3922 }
3923 return rc;
3924}
3925
3926#define DEF_VAR(v,name_str) do {\
3927 (v).name = (name_str);\
3928 (v).name_size = GRN_STRLEN(name_str);\
3929 GRN_TEXT_INIT(&(v).value, 0);\
3930} while (0)
3931
3932#define DEF_COMMAND(name, func, nvars, vars)\
3933 (grn_proc_create(ctx, (name), (sizeof(name) - 1),\
3934 GRN_PROC_COMMAND, (func), NULL, NULL, (nvars), (vars)))
3935
3936void
3937grn_db_init_builtin_commands(grn_ctx *ctx)
3938{
3939 grn_expr_var vars[10];
3940
3941 grn_proc_init_define_selector(ctx);
3942 grn_proc_init_select(ctx);
3943
3944 DEF_VAR(vars[0], "values");
3945 DEF_VAR(vars[1], "table");
3946 DEF_VAR(vars[2], "columns");
3947 DEF_VAR(vars[3], "ifexists");
3948 DEF_VAR(vars[4], "input_type");
3949 DEF_VAR(vars[5], "each");
3950 DEF_VAR(vars[6], "output_ids");
3951 DEF_VAR(vars[7], "output_errors");
3952 DEF_COMMAND("load", proc_load, 8, vars);
3953
3954 DEF_COMMAND("status", proc_status, 0, vars);
3955
3956 grn_proc_init_table_list(ctx);
3957
3958 grn_proc_init_column_list(ctx);
3959
3960 grn_proc_init_table_create(ctx);
3961
3962 grn_proc_init_table_remove(ctx);
3963
3964 grn_proc_init_table_rename(ctx);
3965
3966 grn_proc_init_column_create(ctx);
3967
3968 grn_proc_init_column_remove(ctx);
3969
3970 grn_proc_init_column_rename(ctx);
3971
3972 DEF_VAR(vars[0], "path");
3973 DEF_COMMAND(GRN_EXPR_MISSING_NAME, proc_missing, 1, vars);
3974
3975 DEF_COMMAND("quit", proc_quit, 0, vars);
3976
3977 DEF_VAR(vars[0], "mode");
3978 DEF_COMMAND("shutdown", proc_shutdown, 1, vars);
3979
3980 grn_proc_init_clearlock(ctx);
3981 grn_proc_init_lock_clear(ctx);
3982
3983 DEF_VAR(vars[0], "target_name");
3984 DEF_VAR(vars[1], "threshold");
3985 DEF_COMMAND("defrag", proc_defrag, 2, vars);
3986
3987 DEF_VAR(vars[0], "level");
3988 DEF_COMMAND("log_level", proc_log_level, 1, vars);
3989
3990 DEF_VAR(vars[0], "level");
3991 DEF_VAR(vars[1], "message");
3992 DEF_COMMAND("log_put", proc_log_put, 2, vars);
3993
3994 DEF_COMMAND("log_reopen", proc_log_reopen, 0, vars);
3995
3996 DEF_VAR(vars[0], "table");
3997 DEF_VAR(vars[1], "key");
3998 DEF_VAR(vars[2], "id");
3999 DEF_VAR(vars[3], "filter");
4000 DEF_COMMAND("delete", proc_delete, 4, vars);
4001
4002 DEF_VAR(vars[0], "max");
4003 DEF_COMMAND("cache_limit", proc_cache_limit, 1, vars);
4004
4005 grn_proc_init_dump(ctx);
4006
4007 /* Deprecated. Use "plugin_register" instead. */
4008 DEF_VAR(vars[0], "path");
4009 DEF_COMMAND("register", proc_register, 1, vars);
4010
4011 DEF_VAR(vars[0], "obj");
4012 DEF_COMMAND("check", proc_check, 1, vars);
4013
4014 DEF_VAR(vars[0], "target_name");
4015 DEF_VAR(vars[1], "table");
4016 DEF_COMMAND("truncate", proc_truncate, 2, vars);
4017
4018 DEF_VAR(vars[0], "normalizer");
4019 DEF_VAR(vars[1], "string");
4020 DEF_VAR(vars[2], "flags");
4021 DEF_COMMAND("normalize", proc_normalize, 3, vars);
4022
4023 grn_proc_init_tokenize(ctx);
4024 grn_proc_init_table_tokenize(ctx);
4025
4026 DEF_COMMAND("tokenizer_list", proc_tokenizer_list, 0, vars);
4027
4028 DEF_COMMAND("normalizer_list", proc_normalizer_list, 0, vars);
4029
4030 {
4031 grn_obj *proc;
4032 proc = grn_proc_create(ctx, "rand", -1, GRN_PROC_FUNCTION, func_rand,
4033 NULL, NULL, 0, NULL);
4034 grn_proc_set_is_stable(ctx, proc, GRN_FALSE);
4035 }
4036
4037 {
4038 grn_obj *proc;
4039 proc = grn_proc_create(ctx, "now", -1, GRN_PROC_FUNCTION, func_now,
4040 NULL, NULL, 0, NULL);
4041 grn_proc_set_is_stable(ctx, proc, GRN_FALSE);
4042 }
4043
4044 grn_proc_create(ctx, "max", -1, GRN_PROC_FUNCTION, func_max,
4045 NULL, NULL, 0, NULL);
4046 grn_proc_create(ctx, "min", -1, GRN_PROC_FUNCTION, func_min,
4047 NULL, NULL, 0, NULL);
4048
4049 {
4050 grn_obj *selector_proc;
4051
4052 selector_proc = grn_proc_create(ctx, "geo_in_circle", -1, GRN_PROC_FUNCTION,
4053 func_geo_in_circle, NULL, NULL, 0, NULL);
4054 grn_proc_set_selector(ctx, selector_proc, grn_selector_geo_in_circle);
4055 /* We may need GRN_OP_GEO_IN_CIRCLE. */
4056 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_MATCH);
4057
4058 selector_proc = grn_proc_create(ctx, "geo_in_rectangle", -1,
4059 GRN_PROC_FUNCTION,
4060 func_geo_in_rectangle, NULL, NULL, 0, NULL);
4061 grn_proc_set_selector(ctx, selector_proc, grn_selector_geo_in_rectangle);
4062 /* We may need GRN_OP_GEO_IN_RECTANGLE. */
4063 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_MATCH);
4064 }
4065
4066 grn_proc_create(ctx, "geo_distance", -1, GRN_PROC_FUNCTION,
4067 func_geo_distance, NULL, NULL, 0, NULL);
4068
4069 /* deprecated. */
4070 grn_proc_create(ctx, "geo_distance2", -1, GRN_PROC_FUNCTION,
4071 func_geo_distance2, NULL, NULL, 0, NULL);
4072
4073 /* deprecated. */
4074 grn_proc_create(ctx, "geo_distance3", -1, GRN_PROC_FUNCTION,
4075 func_geo_distance3, NULL, NULL, 0, NULL);
4076
4077 grn_proc_init_edit_distance(ctx);
4078
4079 {
4080 grn_obj *selector_proc;
4081
4082 selector_proc = grn_proc_create(ctx, "all_records", -1, GRN_PROC_FUNCTION,
4083 func_all_records, NULL, NULL, 0, NULL);
4084 grn_proc_set_selector(ctx, selector_proc, selector_all_records);
4085 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
4086 }
4087
4088 /* experimental */
4089 grn_proc_init_snippet_html(ctx);
4090
4091 {
4092 grn_obj *selector_proc;
4093
4094 selector_proc = grn_proc_create(ctx, "query", -1, GRN_PROC_FUNCTION,
4095 func_query, NULL, NULL, 0, NULL);
4096 grn_proc_set_selector(ctx, selector_proc, selector_query);
4097 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
4098 }
4099
4100 {
4101 grn_obj *selector_proc;
4102
4103 selector_proc = grn_proc_create(ctx, "sub_filter", -1, GRN_PROC_FUNCTION,
4104 NULL, NULL, NULL, 0, NULL);
4105 grn_proc_set_selector(ctx, selector_proc, selector_sub_filter);
4106 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
4107 }
4108
4109 grn_proc_create(ctx, "html_untag", -1, GRN_PROC_FUNCTION,
4110 func_html_untag, NULL, NULL, 0, NULL);
4111
4112 {
4113 grn_obj *selector_proc;
4114
4115 selector_proc = grn_proc_create(ctx, "between", -1, GRN_PROC_FUNCTION,
4116 func_between, NULL, NULL, 0, NULL);
4117 grn_proc_set_selector(ctx, selector_proc, selector_between);
4118 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_LESS);
4119 }
4120
4121 grn_proc_init_highlight_html(ctx);
4122 grn_proc_init_highlight_full(ctx);
4123
4124 {
4125 grn_obj *selector_proc;
4126
4127 selector_proc = grn_proc_create(ctx, "in_values", -1, GRN_PROC_FUNCTION,
4128 func_in_values, NULL, NULL, 0, NULL);
4129 grn_proc_set_selector(ctx, selector_proc, selector_in_values);
4130 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_EQUAL);
4131 }
4132
4133 DEF_VAR(vars[0], "table");
4134 DEF_VAR(vars[1], "column");
4135 DEF_VAR(vars[2], "min");
4136 DEF_VAR(vars[3], "min_border");
4137 DEF_VAR(vars[4], "max");
4138 DEF_VAR(vars[5], "max_border");
4139 DEF_VAR(vars[6], "offset");
4140 DEF_VAR(vars[7], "limit");
4141 DEF_VAR(vars[8], "filter");
4142 DEF_VAR(vars[9], "output_columns");
4143 DEF_COMMAND("range_filter", proc_range_filter, 10, vars);
4144
4145 DEF_VAR(vars[0], "id");
4146 DEF_COMMAND("request_cancel", proc_request_cancel, 1, vars);
4147
4148 DEF_VAR(vars[0], "name");
4149 DEF_COMMAND("plugin_register", proc_plugin_register, 1, vars);
4150
4151 DEF_VAR(vars[0], "name");
4152 DEF_COMMAND("plugin_unregister", proc_plugin_unregister, 1, vars);
4153
4154 DEF_VAR(vars[0], "target_name");
4155 DEF_VAR(vars[1], "recursive");
4156 DEF_VAR(vars[2], "only_opened");
4157 DEF_COMMAND("io_flush", proc_io_flush, 3, vars);
4158
4159 grn_proc_init_object_exist(ctx);
4160
4161 DEF_VAR(vars[0], "max");
4162 DEF_COMMAND("thread_limit", proc_thread_limit, 1, vars);
4163
4164 DEF_COMMAND("database_unmap", proc_database_unmap, 0, vars);
4165
4166 grn_proc_init_column_copy(ctx);
4167
4168 grn_proc_init_schema(ctx);
4169
4170 DEF_VAR(vars[0], "target_name");
4171 DEF_COMMAND("reindex", proc_reindex, 1, vars);
4172
4173 {
4174 grn_obj *selector_proc;
4175
4176 selector_proc = grn_proc_create(ctx, "prefix_rk_search", -1,
4177 GRN_PROC_FUNCTION,
4178 NULL, NULL, NULL, 0, NULL);
4179 grn_proc_set_selector(ctx, selector_proc, selector_prefix_rk_search);
4180 grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_PREFIX);
4181 }
4182
4183 grn_proc_init_config_get(ctx);
4184 grn_proc_init_config_set(ctx);
4185 grn_proc_init_config_delete(ctx);
4186
4187 grn_proc_init_lock_acquire(ctx);
4188 grn_proc_init_lock_release(ctx);
4189
4190 grn_proc_init_object_inspect(ctx);
4191
4192 grn_proc_init_fuzzy_search(ctx);
4193
4194 grn_proc_init_object_remove(ctx);
4195
4196 grn_proc_init_snippet(ctx);
4197 grn_proc_init_highlight(ctx);
4198
4199 grn_proc_init_query_expand(ctx);
4200
4201 grn_proc_init_object_list(ctx);
4202
4203 grn_proc_init_table_copy(ctx);
4204
4205 grn_proc_init_in_records(ctx);
4206
4207 grn_proc_init_query_log_flags_get(ctx);
4208 grn_proc_init_query_log_flags_set(ctx);
4209 grn_proc_init_query_log_flags_add(ctx);
4210 grn_proc_init_query_log_flags_remove(ctx);
4211}
4212