Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
proc.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2 -*- */
2 /*
3  Copyright(C) 2009-2013 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 "proc.h"
20 #include "ii.h"
21 #include "db.h"
22 #include "util.h"
23 #include "output.h"
24 #include "pat.h"
25 #include "geo.h"
26 #include "token.h"
27 
28 #include <string.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 
33 #ifndef O_NOFOLLOW
34 #define O_NOFOLLOW 0
35 #endif
36 
37 #ifndef O_BINARY
38 #define O_BINARY 0
39 #endif
40 
42  const char *term,
43  unsigned int term_len,
44  grn_obj *substituted_term,
45  grn_user_data *user_data);
46 typedef struct {
50 
51 /**** globals for procs ****/
52 const char *grn_document_root = NULL;
53 
54 #define VAR GRN_PROC_GET_VAR_BY_OFFSET
55 
56 #define GRN_SELECT_INTERNAL_VAR_CONDITION "$condition"
57 #define GRN_SELECT_INTERNAL_VAR_MATCH_COLUMNS "$match_columns"
58 
59 /* bulk must be initialized grn_bulk or grn_msg */
60 static int
61 grn_bulk_put_from_file(grn_ctx *ctx, grn_obj *bulk, const char *path)
62 {
63  /* FIXME: implement more smartly with grn_bulk */
64  int fd, ret = 0;
65  struct stat stat;
66  if ((fd = GRN_OPEN(path, O_RDONLY|O_NOFOLLOW|O_BINARY)) == -1) {
67  switch (errno) {
68  case EACCES :
69  ERR(GRN_OPERATION_NOT_PERMITTED, "request is not allowed: <%s>", path);
70  break;
71  case ENOENT :
72  ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY, "no such file: <%s>", path);
73  break;
74 #ifndef WIN32
75  case ELOOP :
77  "symbolic link is not allowed: <%s>", path);
78  break;
79 #endif /* WIN32 */
80  default :
81  ERR(GRN_UNKNOWN_ERROR, "GRN_OPEN() failed(errno: %d): <%s>", errno, path);
82  break;
83  }
84  return 0;
85  }
86  if (fstat(fd, &stat) != -1) {
87  char *buf, *bp;
88  off_t rest = stat.st_size;
89  if ((buf = GRN_MALLOC(rest))) {
90  ssize_t ss;
91  for (bp = buf; rest; rest -= ss, bp += ss) {
92  if ((ss = GRN_READ(fd, bp, rest)) == -1) { goto exit; }
93  }
94  GRN_TEXT_PUT(ctx, bulk, buf, stat.st_size);
95  ret = 1;
96  }
97  GRN_FREE(buf);
98  } else {
99  ERR(GRN_INVALID_ARGUMENT, "cannot stat file: <%s>", path);
100  }
101 exit :
102  GRN_CLOSE(fd);
103  return ret;
104 }
105 
106 #ifdef stat
107 # undef stat
108 #endif /* stat */
109 
110 /**** query expander ****/
111 
112 static grn_rc
113 substitute_term_by_func(grn_ctx *ctx, const char *term, unsigned int term_len,
114  grn_obj *expanded_term, grn_user_data *user_data)
115 {
116  grn_rc rc;
117  grn_obj *expander = user_data->ptr;
118  grn_obj grn_term;
119  grn_obj *caller;
120  grn_obj *rc_object;
121  int nargs = 0;
122 
124  GRN_TEXT_SET(ctx, &grn_term, term, term_len);
125  grn_ctx_push(ctx, &grn_term);
126  nargs++;
127  grn_ctx_push(ctx, expanded_term);
128  nargs++;
129 
130  caller = grn_expr_create(ctx, NULL, 0);
131  rc = grn_proc_call(ctx, expander, nargs, caller);
132  GRN_OBJ_FIN(ctx, &grn_term);
133  rc_object = grn_ctx_pop(ctx);
134  rc = GRN_INT32_VALUE(rc_object);
135  grn_obj_unlink(ctx, caller);
136 
137  return rc;
138 }
139 
140 static grn_rc
141 substitute_term_by_column(grn_ctx *ctx, const char *term, unsigned int term_len,
142  grn_obj *expanded_term, grn_user_data *user_data)
143 {
144  grn_rc rc = GRN_END_OF_DATA;
145  grn_id id;
146  grn_substitute_term_by_column_data *data = user_data->ptr;
147  grn_obj *table, *column;
148 
149  table = data->table;
150  column = data->column;
151  if ((id = grn_table_get(ctx, table, term, term_len))) {
152  if ((column->header.type == GRN_COLUMN_VAR_SIZE) &&
154  unsigned int i, n;
155  grn_obj values;
156  GRN_TEXT_INIT(&values, GRN_OBJ_VECTOR);
157  grn_obj_get_value(ctx, column, id, &values);
158  n = grn_vector_size(ctx, &values);
159  if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
160  for (i = 0; i < n; i++) {
161  const char *value;
162  unsigned int length;
163  if (i > 0) {
164  GRN_TEXT_PUTS(ctx, expanded_term, " OR ");
165  }
166  if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
167  length = grn_vector_get_element(ctx, &values, i, &value, NULL, NULL);
168  GRN_TEXT_PUT(ctx, expanded_term, value, length);
169  if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
170  }
171  if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
172  GRN_OBJ_FIN(ctx, &values);
173  } else {
174  grn_obj_get_value(ctx, column, id, expanded_term);
175  }
176  rc = GRN_SUCCESS;
177  }
178  return rc;
179 }
180 
181 static grn_rc
182 substitute_terms(grn_ctx *ctx, const char *query, unsigned int query_len,
183  grn_expr_flags flags,
184  grn_obj *expanded_query,
185  grn_substitute_term_func substitute_term_func,
186  grn_user_data *user_data)
187 {
188  grn_obj buf;
189  unsigned int len;
190  const char *start, *cur = query, *query_end = query + (size_t)query_len;
191  GRN_TEXT_INIT(&buf, 0);
192  for (;;) {
193  while (cur < query_end && grn_isspace(cur, ctx->encoding)) {
194  if (!(len = grn_charlen(ctx, cur, query_end))) { goto exit; }
195  GRN_TEXT_PUT(ctx, expanded_query, cur, len);
196  cur += len;
197  }
198  if (query_end <= cur) { break; }
199  switch (*cur) {
200  case '\0' :
201  goto exit;
202  break;
203  case GRN_QUERY_AND :
204  case GRN_QUERY_ADJ_INC :
205  case GRN_QUERY_ADJ_DEC :
206  case GRN_QUERY_ADJ_NEG :
207  case GRN_QUERY_AND_NOT :
208  case GRN_QUERY_PARENL :
209  case GRN_QUERY_PARENR :
210  case GRN_QUERY_PREFIX :
211  GRN_TEXT_PUTC(ctx, expanded_query, *cur);
212  cur++;
213  break;
214  case GRN_QUERY_QUOTEL :
215  GRN_BULK_REWIND(&buf);
216  for (start = cur++; cur < query_end; cur += len) {
217  if (!(len = grn_charlen(ctx, cur, query_end))) {
218  goto exit;
219  } else if (len == 1) {
220  if (*cur == GRN_QUERY_QUOTER) {
221  cur++;
222  break;
223  } else if (cur + 1 < query_end && *cur == GRN_QUERY_ESCAPE) {
224  cur++;
225  len = grn_charlen(ctx, cur, query_end);
226  }
227  }
228  GRN_TEXT_PUT(ctx, &buf, cur, len);
229  }
230  if (substitute_term_func(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf),
231  expanded_query, user_data)) {
232  GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
233  }
234  break;
235  case 'O' :
236  if (cur + 2 <= query_end && cur[1] == 'R' &&
237  (cur + 2 == query_end || grn_isspace(cur + 2, ctx->encoding))) {
238  GRN_TEXT_PUT(ctx, expanded_query, cur, 2);
239  cur += 2;
240  break;
241  }
242  /* fallthru */
243  default :
244  for (start = cur; cur < query_end; cur += len) {
245  if (!(len = grn_charlen(ctx, cur, query_end))) {
246  goto exit;
247  } else if (grn_isspace(cur, ctx->encoding)) {
248  break;
249  } else if (len == 1) {
250  if (*cur == GRN_QUERY_PARENL ||
251  *cur == GRN_QUERY_PARENR ||
252  *cur == GRN_QUERY_PREFIX) {
253  break;
254  } else if (flags & GRN_EXPR_ALLOW_COLUMN && *cur == GRN_QUERY_COLUMN) {
255  if (cur + 1 < query_end) {
256  switch (cur[1]) {
257  case '!' :
258  case '@' :
259  case '^' :
260  case '$' :
261  cur += 2;
262  break;
263  case '=' :
264  cur += (flags & GRN_EXPR_ALLOW_UPDATE) ? 2 : 1;
265  break;
266  case '<' :
267  case '>' :
268  cur += (cur + 2 < query_end && cur[2] == '=') ? 3 : 2;
269  break;
270  default :
271  cur += 1;
272  break;
273  }
274  } else {
275  cur += 1;
276  }
277  GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
278  start = cur;
279  break;
280  }
281  }
282  }
283  if (start < cur) {
284  if (substitute_term_func(ctx, start, cur - start,
285  expanded_query, user_data)) {
286  GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
287  }
288  }
289  break;
290  }
291  }
292 exit :
293  GRN_OBJ_FIN(ctx, &buf);
294  return GRN_SUCCESS;
295 }
296 
297 static grn_rc
298 expand_query(grn_ctx *ctx, const char *query, unsigned int query_len,
299  grn_expr_flags flags,
300  const char *query_expander_name,
301  unsigned int query_expander_name_len,
302  grn_obj *expanded_query)
303 {
304  grn_rc rc = GRN_SUCCESS;
305  grn_obj *query_expander;
306 
307  query_expander = grn_ctx_get(ctx,
308  query_expander_name, query_expander_name_len);
309  if (!query_expander) {
311  "nonexistent query expansion column: <%.*s>",
312  query_expander_name_len, query_expander_name);
313  return GRN_INVALID_ARGUMENT;
314  }
315 
316  switch (query_expander->header.type) {
317  case GRN_PROC :
318  if (((grn_proc *)query_expander)->type == GRN_PROC_FUNCTION) {
319  grn_user_data user_data;
320  user_data.ptr = query_expander;
321  substitute_terms(ctx, query, query_len, flags, expanded_query,
322  substitute_term_by_func, &user_data);
323  } else {
325  ERR(rc,
326  "[expand-query] must be function proc: <%.*s>",
327  query_expander_name_len, query_expander_name);
328  }
329  break;
330  case GRN_COLUMN_FIX_SIZE :
331  case GRN_COLUMN_VAR_SIZE :
332  {
333  grn_obj *query_expansion_table;
334  query_expansion_table = grn_column_table(ctx, query_expander);
335  if (query_expansion_table) {
336  grn_user_data user_data;
338  user_data.ptr = &data;
339  data.table = query_expansion_table;
340  data.column = query_expander;
341  substitute_terms(ctx, query, query_len, flags, expanded_query,
342  substitute_term_by_column, &user_data);
343  grn_obj_unlink(ctx, query_expansion_table);
344  } else {
346  ERR(rc,
347  "[expand-query] failed to get table of column: <%.*s>",
348  query_expander_name_len, query_expander_name);
349  }
350  }
351  break;
352  default :
354  {
355  grn_obj type_name;
356  GRN_TEXT_INIT(&type_name, 0);
357  grn_inspect_type(ctx, &type_name, query_expander->header.type);
358  ERR(rc,
359  "[expand-query] must be a column or function proc: <%.*s>(%.*s)",
360  query_expander_name_len, query_expander_name,
361  (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
362  GRN_OBJ_FIN(ctx, &type_name);
363  }
364  break;
365  }
366  grn_obj_unlink(ctx, query_expander);
367 
368  return rc;
369 }
370 
371 
372 /**** procs ****/
373 
374 #define DEFAULT_LIMIT 10
375 #define DEFAULT_OUTPUT_COLUMNS "_id, _key, *"
376 #define DEFAULT_DRILLDOWN_LIMIT 10
377 #define DEFAULT_DRILLDOWN_OUTPUT_COLUMNS "_key, _nsubrecs"
378 #define DUMP_COLUMNS "_id, _key, _value, *"
379 
380 static grn_expr_flags
381 grn_parse_query_flags(grn_ctx *ctx, const char *query_flags,
382  unsigned int query_flags_len)
383 {
384  grn_expr_flags flags = 0;
385  const char *query_flags_end = query_flags + query_flags_len;
386 
387  while (query_flags < query_flags_end) {
388  if (*query_flags == '|' || *query_flags == ' ') {
389  query_flags += 1;
390  continue;
391  }
392 
393 #define CHECK_EXPR_FLAG(name)\
394  if (((query_flags_end - query_flags) >= (sizeof(#name) - 1)) &&\
395  (!memcmp(query_flags, #name, sizeof(#name) - 1))) {\
396  flags |= GRN_EXPR_ ## name;\
397  query_flags += sizeof(#name);\
398  continue;\
399  }
400 
401  CHECK_EXPR_FLAG(ALLOW_PRAGMA);
402  CHECK_EXPR_FLAG(ALLOW_COLUMN);
403  CHECK_EXPR_FLAG(ALLOW_UPDATE);
404  CHECK_EXPR_FLAG(ALLOW_LEADING_NOT);
405 
406 #define GRN_EXPR_NONE 0
407  CHECK_EXPR_FLAG(NONE);
408 #undef GNR_EXPR_NONE
409 
410  ERR(GRN_INVALID_ARGUMENT, "invalid query flag: <%.*s>",
411  (int)(query_flags_end - query_flags), query_flags);
412  return 0;
413 #undef CHECK_EXPR_FLAG
414  }
415 
416  return flags;
417 }
418 
419 static inline grn_bool
420 is_output_columns_format_v1(grn_ctx *ctx,
421  const char *output_columns,
422  unsigned int output_columns_len)
423 {
424  unsigned int i;
425 
426  /* TODO: REMOVE ME. If new output_columns handler is marked as stable,
427  this check is removed. We need more error checks. */
429  return GRN_TRUE;
430  }
431 
432  for (i = 0; i < output_columns_len; i++) {
433  switch (output_columns[i]) {
434  case ',' :
435  case '(' :
436  return GRN_FALSE;
437  default :
438  break;
439  }
440  }
441 
442  return GRN_TRUE;
443 }
444 
445 grn_rc
446 grn_select(grn_ctx *ctx, const char *table, unsigned int table_len,
447  const char *match_columns, unsigned int match_columns_len,
448  const char *query, unsigned int query_len,
449  const char *filter, unsigned int filter_len,
450  const char *scorer, unsigned int scorer_len,
451  const char *sortby, unsigned int sortby_len,
452  const char *output_columns, unsigned int output_columns_len,
453  int offset, int limit,
454  const char *drilldown, unsigned int drilldown_len,
455  const char *drilldown_sortby, unsigned int drilldown_sortby_len,
456  const char *drilldown_output_columns, unsigned int drilldown_output_columns_len,
457  int drilldown_offset, int drilldown_limit,
458  const char *cache, unsigned int cache_len,
459  const char *match_escalation_threshold, unsigned int match_escalation_threshold_len,
460  const char *query_expander, unsigned int query_expander_len,
461  const char *query_flags, unsigned int query_flags_len)
462 {
463  uint32_t nkeys, nhits;
464  uint16_t cacheable = 1, taintable = 0;
465  grn_obj_format format;
466  grn_table_sort_key *keys;
467  grn_obj *outbuf = ctx->impl->outbuf;
468  grn_content_type output_type = ctx->impl->output_type;
469  grn_obj *table_, *match_columns_ = NULL, *cond = NULL, *scorer_, *res = NULL, *sorted;
470  char cache_key[GRN_TABLE_MAX_KEY_SIZE];
471  uint32_t cache_key_size = table_len + 1 + match_columns_len + 1 + query_len + 1 +
472  filter_len + 1 + scorer_len + 1 + sortby_len + 1 + output_columns_len + 1 +
473  drilldown_len + 1 + drilldown_sortby_len + 1 +
474  drilldown_output_columns_len + 1 + match_escalation_threshold_len + 1 +
475  query_expander_len + 1 + query_flags_len + 1 +
476  sizeof(grn_content_type) + sizeof(int) * 4;
477  long long int threshold, original_threshold = 0;
478  grn_cache *cache_obj = grn_cache_current_get(ctx);
479  if (cache_key_size <= GRN_TABLE_MAX_KEY_SIZE) {
480  grn_obj *cache_value;
481  char *cp = cache_key;
482  memcpy(cp, table, table_len);
483  cp += table_len; *cp++ = '\0';
484  memcpy(cp, match_columns, match_columns_len);
485  cp += match_columns_len; *cp++ = '\0';
486  memcpy(cp, query, query_len);
487  cp += query_len; *cp++ = '\0';
488  memcpy(cp, filter, filter_len);
489  cp += filter_len; *cp++ = '\0';
490  memcpy(cp, scorer, scorer_len);
491  cp += scorer_len; *cp++ = '\0';
492  memcpy(cp, sortby, sortby_len);
493  cp += sortby_len; *cp++ = '\0';
494  memcpy(cp, output_columns, output_columns_len);
495  cp += output_columns_len; *cp++ = '\0';
496  memcpy(cp, drilldown, drilldown_len);
497  cp += drilldown_len; *cp++ = '\0';
498  memcpy(cp, drilldown_sortby, drilldown_sortby_len);
499  cp += drilldown_sortby_len; *cp++ = '\0';
500  memcpy(cp, drilldown_output_columns, drilldown_output_columns_len);
501  cp += drilldown_output_columns_len; *cp++ = '\0';
502  memcpy(cp, match_escalation_threshold, match_escalation_threshold_len);
503  cp += match_escalation_threshold_len; *cp++ = '\0';
504  memcpy(cp, query_expander, query_expander_len);
505  cp += query_expander_len; *cp++ = '\0';
506  memcpy(cp, query_flags, query_flags_len);
507  cp += query_flags_len; *cp++ = '\0';
508  memcpy(cp, &output_type, sizeof(grn_content_type)); cp += sizeof(grn_content_type);
509  memcpy(cp, &offset, sizeof(int)); cp += sizeof(int);
510  memcpy(cp, &limit, sizeof(int)); cp += sizeof(int);
511  memcpy(cp, &drilldown_offset, sizeof(int)); cp += sizeof(int);
512  memcpy(cp, &drilldown_limit, sizeof(int)); cp += sizeof(int);
513  cache_value = grn_cache_fetch(ctx, cache_obj, cache_key, cache_key_size);
514  if (cache_value) {
515  GRN_TEXT_PUT(ctx, outbuf,
516  GRN_TEXT_VALUE(cache_value),
517  GRN_TEXT_LEN(cache_value));
518  grn_cache_unref(ctx, cache_obj, cache_key, cache_key_size);
520  ":", "cache(%" GRN_FMT_LLD ")",
521  (long long int)GRN_TEXT_LEN(cache_value));
522  return ctx->rc;
523  }
524  }
525  if (match_escalation_threshold_len) {
526  const char *end, *rest;
527  original_threshold = grn_ctx_get_match_escalation_threshold(ctx);
528  end = match_escalation_threshold + match_escalation_threshold_len;
529  threshold = grn_atoll(match_escalation_threshold, end, &rest);
530  if (end == rest) {
532  }
533  }
534  if ((table_ = grn_ctx_get(ctx, table, table_len))) {
535  // match_columns_ = grn_obj_column(ctx, table_, match_columns, match_columns_len);
536  if (query_len || filter_len) {
537  grn_obj *v;
538  GRN_EXPR_CREATE_FOR_QUERY(ctx, table_, cond, v);
539  if (cond) {
540  if (match_columns_len) {
541  GRN_EXPR_CREATE_FOR_QUERY(ctx, table_, match_columns_, v);
542  if (match_columns_) {
543  grn_expr_parse(ctx, match_columns_, match_columns, match_columns_len,
544  NULL, GRN_OP_MATCH, GRN_OP_AND,
546  } else {
547  /* todo */
548  }
549  }
550  if (query_len) {
551  grn_expr_flags flags;
552  grn_obj query_expander_buf;
553  GRN_TEXT_INIT(&query_expander_buf, 0);
554  flags = GRN_EXPR_SYNTAX_QUERY;
555  if (query_flags_len) {
556  flags |= grn_parse_query_flags(ctx, query_flags, query_flags_len);
557  } else {
559  if (ctx->rc) {
560  goto exit;
561  }
562  }
563  if (query_expander_len) {
564  if (expand_query(ctx, query, query_len, flags,
565  query_expander, query_expander_len,
566  &query_expander_buf) == GRN_SUCCESS) {
567  query = GRN_TEXT_VALUE(&query_expander_buf);
568  query_len = GRN_TEXT_LEN(&query_expander_buf);
569  } else {
570  GRN_OBJ_FIN(ctx, &query_expander_buf);
571  goto exit;
572  }
573  }
574  grn_expr_parse(ctx, cond, query, query_len,
575  match_columns_, GRN_OP_MATCH, GRN_OP_AND, flags);
576  GRN_OBJ_FIN(ctx, &query_expander_buf);
577  if (!ctx->rc && filter_len) {
578  grn_expr_parse(ctx, cond, filter, filter_len,
579  match_columns_, GRN_OP_MATCH, GRN_OP_AND,
581  if (!ctx->rc) { grn_expr_append_op(ctx, cond, GRN_OP_AND, 2); }
582  }
583  } else {
584  grn_expr_parse(ctx, cond, filter, filter_len,
585  match_columns_, GRN_OP_MATCH, GRN_OP_AND,
587  }
588  cacheable *= ((grn_expr *)cond)->cacheable;
589  taintable += ((grn_expr *)cond)->taintable;
590  /*
591  grn_obj strbuf;
592  GRN_TEXT_INIT(&strbuf, 0);
593  grn_expr_inspect(ctx, &strbuf, cond);
594  GRN_TEXT_PUTC(ctx, &strbuf, '\0');
595  GRN_LOG(ctx, GRN_LOG_NOTICE, "query=(%s)", GRN_TEXT_VALUE(&strbuf));
596  GRN_OBJ_FIN(ctx, &strbuf);
597  */
598  if (!ctx->rc) { res = grn_table_select(ctx, table_, cond, NULL, GRN_OP_OR); }
599  } else {
600  /* todo */
601  ERRCLR(ctx);
602  }
603  } else {
604  res = table_;
605  }
606  nhits = res ? grn_table_size(ctx, res) : 0;
608  ":", "select(%d)", nhits);
609 
610  if (res) {
611  uint32_t ngkeys;
612  grn_table_sort_key *gkeys = NULL;
613  int result_size = 1;
614  if (!ctx->rc && drilldown_len) {
615  gkeys = grn_table_sort_key_from_str(ctx,
616  drilldown, drilldown_len,
617  res, &ngkeys);
618  if (gkeys) {
619  result_size += ngkeys;
620  }
621  }
622  GRN_OUTPUT_ARRAY_OPEN("RESULT", result_size);
623 
624  if (scorer && scorer_len) {
625  grn_obj *v;
626  GRN_EXPR_CREATE_FOR_QUERY(ctx, res, scorer_, v);
627  if (scorer_ && v) {
628  grn_table_cursor *tc;
629  grn_expr_parse(ctx, scorer_, scorer, scorer_len, NULL, GRN_OP_MATCH, GRN_OP_AND,
631  cacheable *= ((grn_expr *)scorer_)->cacheable;
632  taintable += ((grn_expr *)scorer_)->taintable;
633  if ((tc = grn_table_cursor_open(ctx, res, NULL, 0, NULL, 0, 0, -1, 0))) {
634  grn_id id;
635  while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
636  GRN_RECORD_SET(ctx, v, id);
637  grn_expr_exec(ctx, scorer_, 0);
638  }
639  grn_table_cursor_close(ctx, tc);
640  }
641  grn_obj_unlink(ctx, scorer_);
642  }
644  ":", "score(%d)", nhits);
645  }
646 
647  grn_normalize_offset_and_limit(ctx, nhits, &offset, &limit);
648 
649  if (sortby_len &&
650  (keys = grn_table_sort_key_from_str(ctx, sortby, sortby_len, res, &nkeys))) {
651  if ((sorted = grn_table_create(ctx, NULL, 0, NULL,
652  GRN_OBJ_TABLE_NO_KEY, NULL, res))) {
653  grn_table_sort(ctx, res, offset, limit, sorted, keys, nkeys);
655  ":", "sort(%d)", limit);
656  GRN_OBJ_FORMAT_INIT(&format, nhits, 0, limit, offset);
657  format.flags =
660  if (is_output_columns_format_v1(ctx, output_columns, output_columns_len)) {
661  grn_obj_columns(ctx, sorted, output_columns, output_columns_len,
662  &format.columns);
663  } else {
664  grn_obj *v;
665  grn_obj *condition_ptr;
666  GRN_EXPR_CREATE_FOR_QUERY(ctx, sorted, format.expression, v);
667  grn_expr_parse(ctx, format.expression,
668  output_columns, output_columns_len, NULL,
671  condition_ptr =
675  GRN_PTR_INIT(condition_ptr, 0, GRN_DB_OBJECT);
676  GRN_PTR_SET(ctx, condition_ptr, cond);
677  }
678  GRN_OUTPUT_OBJ(sorted, &format);
679  GRN_OBJ_FORMAT_FIN(ctx, &format);
680  grn_obj_unlink(ctx, sorted);
681  }
682  grn_table_sort_key_close(ctx, keys, nkeys);
683  } else {
684  if (!ctx->rc) {
685  GRN_OBJ_FORMAT_INIT(&format, nhits, offset, limit, offset);
686  format.flags =
689  if (is_output_columns_format_v1(ctx, output_columns, output_columns_len)) {
690  grn_obj_columns(ctx, res, output_columns, output_columns_len,
691  &format.columns);
692  } else {
693  grn_obj *v;
694  grn_obj *condition_ptr;
695  GRN_EXPR_CREATE_FOR_QUERY(ctx, res, format.expression, v);
696  grn_expr_parse(ctx, format.expression,
697  output_columns, output_columns_len, NULL,
700  condition_ptr =
704  GRN_PTR_INIT(condition_ptr, 0, GRN_DB_OBJECT);
705  GRN_PTR_SET(ctx, condition_ptr, cond);
706  }
707  GRN_OUTPUT_OBJ(res, &format);
708  GRN_OBJ_FORMAT_FIN(ctx, &format);
709  }
710  }
712  ":", "output(%d)", limit);
713  if (!ctx->rc && drilldown_len) {
714  uint32_t i;
715  grn_table_group_result g = {NULL, 0, 0, 1, GRN_TABLE_GROUP_CALC_COUNT, 0};
716  if (gkeys) {
717  for (i = 0; i < ngkeys; i++) {
718  if ((g.table = grn_table_create_for_group(ctx, NULL, 0, NULL,
719  gkeys[i].key, res, 0))) {
720  int n_drilldown_offset = drilldown_offset,
721  n_drilldown_limit = drilldown_limit;
722 
723  grn_table_group(ctx, res, &gkeys[i], 1, &g, 1);
724  nhits = grn_table_size(ctx, g.table);
725 
727  &n_drilldown_offset, &n_drilldown_limit);
728 
729  if (drilldown_sortby_len) {
730  if ((keys = grn_table_sort_key_from_str(ctx,
731  drilldown_sortby, drilldown_sortby_len,
732  g.table, &nkeys))) {
733  if ((sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY,
734  NULL, g.table))) {
735  grn_table_sort(ctx, g.table, n_drilldown_offset, n_drilldown_limit,
736  sorted, keys, nkeys);
737  GRN_OBJ_FORMAT_INIT(&format, nhits, 0,
738  n_drilldown_limit, n_drilldown_offset);
739  format.flags =
742  grn_obj_columns(ctx, sorted,
743  drilldown_output_columns, drilldown_output_columns_len,
744  &format.columns);
745  GRN_OUTPUT_OBJ(sorted, &format);
746  GRN_OBJ_FORMAT_FIN(ctx, &format);
747  grn_obj_unlink(ctx, sorted);
748  }
749  grn_table_sort_key_close(ctx, keys, nkeys);
750  }
751  } else {
752  GRN_OBJ_FORMAT_INIT(&format, nhits, n_drilldown_offset,
753  n_drilldown_limit, n_drilldown_offset);
754  format.flags =
757  grn_obj_columns(ctx, g.table, drilldown_output_columns,
758  drilldown_output_columns_len, &format.columns);
759  GRN_OUTPUT_OBJ(g.table, &format);
760  GRN_OBJ_FORMAT_FIN(ctx, &format);
761  }
762  grn_obj_unlink(ctx, g.table);
763  }
765  ":", "drilldown(%d)", nhits);
766  }
767  grn_table_sort_key_close(ctx, gkeys, ngkeys);
768  }
769  }
770  if (res != table_) { grn_obj_unlink(ctx, res); }
771  } else {
772  GRN_OUTPUT_ARRAY_OPEN("RESULT", 0);
773  }
775  if (!ctx->rc && cacheable && cache_key_size <= GRN_TABLE_MAX_KEY_SIZE
776  && (!cache || cache_len != 2 || *cache != 'n' || *(cache + 1) != 'o')) {
777  grn_cache_update(ctx, cache_obj, cache_key, cache_key_size, outbuf);
778  }
779  if (taintable) { grn_db_touch(ctx, DB_OBJ(table_)->db); }
780  grn_obj_unlink(ctx, table_);
781  } else {
782  ERR(GRN_INVALID_ARGUMENT, "invalid table name: <%.*s>", table_len, table);
783  }
784 exit:
785  if (match_escalation_threshold_len) {
786  grn_ctx_set_match_escalation_threshold(ctx, original_threshold);
787  }
788  if (match_columns_) {
789  grn_obj_unlink(ctx, match_columns_);
790  }
791  if (cond) {
792  grn_obj_unlink(ctx, cond);
793  }
794  /* GRN_LOG(ctx, GRN_LOG_NONE, "%d", ctx->seqno); */
795  return ctx->rc;
796 }
797 
798 static grn_obj *
799 proc_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
800 {
801  int offset = GRN_TEXT_LEN(VAR(7))
802  ? grn_atoi(GRN_TEXT_VALUE(VAR(7)), GRN_BULK_CURR(VAR(7)), NULL)
803  : 0;
804  int limit = GRN_TEXT_LEN(VAR(8))
805  ? grn_atoi(GRN_TEXT_VALUE(VAR(8)), GRN_BULK_CURR(VAR(8)), NULL)
806  : DEFAULT_LIMIT;
807  const char *output_columns = GRN_TEXT_VALUE(VAR(6));
808  uint32_t output_columns_len = GRN_TEXT_LEN(VAR(6));
809  const char *drilldown_output_columns = GRN_TEXT_VALUE(VAR(11));
810  uint32_t drilldown_output_columns_len = GRN_TEXT_LEN(VAR(11));
811  int drilldown_offset = GRN_TEXT_LEN(VAR(12))
812  ? grn_atoi(GRN_TEXT_VALUE(VAR(12)), GRN_BULK_CURR(VAR(12)), NULL)
813  : 0;
814  int drilldown_limit = GRN_TEXT_LEN(VAR(13))
815  ? grn_atoi(GRN_TEXT_VALUE(VAR(13)), GRN_BULK_CURR(VAR(13)), NULL)
817  grn_obj *query_expansion = VAR(16);
818  grn_obj *query_expander = VAR(18);
819  if (GRN_TEXT_LEN(query_expander) == 0 && GRN_TEXT_LEN(query_expansion) > 0) {
820  query_expander = query_expansion;
821  }
822  if (!output_columns_len) {
823  output_columns = DEFAULT_OUTPUT_COLUMNS;
824  output_columns_len = strlen(DEFAULT_OUTPUT_COLUMNS);
825  }
826  if (!drilldown_output_columns_len) {
827  drilldown_output_columns = DEFAULT_DRILLDOWN_OUTPUT_COLUMNS;
828  drilldown_output_columns_len = strlen(DEFAULT_DRILLDOWN_OUTPUT_COLUMNS);
829  }
830  if (grn_select(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)),
836  output_columns, output_columns_len,
837  offset, limit,
839  GRN_TEXT_VALUE(VAR(10)), GRN_TEXT_LEN(VAR(10)),
840  drilldown_output_columns, drilldown_output_columns_len,
841  drilldown_offset, drilldown_limit,
842  GRN_TEXT_VALUE(VAR(14)), GRN_TEXT_LEN(VAR(14)),
843  GRN_TEXT_VALUE(VAR(15)), GRN_TEXT_LEN(VAR(15)),
844  GRN_TEXT_VALUE(query_expander), GRN_TEXT_LEN(query_expander),
845  GRN_TEXT_VALUE(VAR(17)), GRN_TEXT_LEN(VAR(17)))) {
846  }
847  return NULL;
848 }
849 
850 static grn_obj *
851 proc_define_selector(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
852 {
853  uint32_t i, nvars;
854  grn_expr_var *vars;
855  grn_proc_get_info(ctx, user_data, &vars, &nvars, NULL);
856  for (i = 1; i < nvars; i++) {
857  GRN_TEXT_SET(ctx, &((vars + i)->value),
859  }
860  grn_proc_create(ctx,
862  GRN_PROC_COMMAND, proc_select, NULL, NULL, nvars - 1, vars + 1);
863  GRN_OUTPUT_BOOL(!ctx->rc);
864  return NULL;
865 }
866 
867 static grn_obj *
868 proc_load(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
869 {
870  grn_load(ctx, grn_get_ctype(VAR(4)),
876  if (ctx->impl->loader.stat != GRN_LOADER_END) {
877  grn_ctx_set_next_expr(ctx, grn_proc_get_info(ctx, user_data, NULL, NULL, NULL));
878  } else {
880  if (ctx->impl->loader.table) {
881  grn_db_touch(ctx, DB_OBJ(ctx->impl->loader.table)->db);
882  }
883  /* maybe necessary : grn_ctx_loader_clear(ctx); */
884  }
885  return NULL;
886 }
887 
888 static grn_obj *
889 proc_status(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
890 {
891  grn_timeval now;
892  grn_cache *cache;
893  grn_cache_statistics statistics;
894 
895  grn_timeval_now(ctx, &now);
896  cache = grn_cache_current_get(ctx);
897  grn_cache_get_statistics(ctx, cache, &statistics);
898  GRN_OUTPUT_MAP_OPEN("RESULT", 18);
899  GRN_OUTPUT_CSTR("alloc_count");
901  GRN_OUTPUT_CSTR("starttime");
903  GRN_OUTPUT_CSTR("uptime");
905  GRN_OUTPUT_CSTR("version");
907  GRN_OUTPUT_CSTR("n_queries");
908  GRN_OUTPUT_INT64(statistics.nfetches);
909  GRN_OUTPUT_CSTR("cache_hit_rate");
910  if (statistics.nfetches == 0) {
911  GRN_OUTPUT_FLOAT(0.0);
912  } else {
913  double cache_hit_rate;
914  cache_hit_rate = (double)statistics.nhits / (double)statistics.nfetches;
915  GRN_OUTPUT_FLOAT(cache_hit_rate * 100.0);
916  }
917  GRN_OUTPUT_CSTR("command_version");
919  GRN_OUTPUT_CSTR("default_command_version");
921  GRN_OUTPUT_CSTR("max_command_version");
924  return NULL;
925 }
926 
927 static grn_obj_flags
928 grn_parse_table_create_flags(grn_ctx *ctx, const char *nptr, const char *end)
929 {
930  grn_obj_flags flags = 0;
931  while (nptr < end) {
932  if (*nptr == '|' || *nptr == ' ') {
933  nptr += 1;
934  continue;
935  }
936  if (!memcmp(nptr, "TABLE_HASH_KEY", 14)) {
937  flags |= GRN_OBJ_TABLE_HASH_KEY;
938  nptr += 14;
939  } else if (!memcmp(nptr, "TABLE_PAT_KEY", 13)) {
940  flags |= GRN_OBJ_TABLE_PAT_KEY;
941  nptr += 13;
942  } else if (!memcmp(nptr, "TABLE_DAT_KEY", 13)) {
943  flags |= GRN_OBJ_TABLE_DAT_KEY;
944  nptr += 13;
945  } else if (!memcmp(nptr, "TABLE_NO_KEY", 12)) {
946  flags |= GRN_OBJ_TABLE_NO_KEY;
947  nptr += 12;
948  } else if (!memcmp(nptr, "KEY_NORMALIZE", 13)) {
949  flags |= GRN_OBJ_KEY_NORMALIZE;
950  nptr += 13;
951  } else if (!memcmp(nptr, "KEY_WITH_SIS", 12)) {
952  flags |= GRN_OBJ_KEY_WITH_SIS;
953  nptr += 12;
954  } else {
955  ERR(GRN_INVALID_ARGUMENT, "invalid flags option: %.*s",
956  (int)(end - nptr), nptr);
957  return 0;
958  }
959  }
960  return flags;
961 }
962 
963 static grn_obj_flags
964 grn_parse_column_create_flags(grn_ctx *ctx, const char *nptr, const char *end)
965 {
966  grn_obj_flags flags = 0;
967  while (nptr < end) {
968  if (*nptr == '|' || *nptr == ' ') {
969  nptr += 1;
970  continue;
971  }
972  if (!memcmp(nptr, "COLUMN_SCALAR", 13)) {
973  flags |= GRN_OBJ_COLUMN_SCALAR;
974  nptr += 13;
975  } else if (!memcmp(nptr, "COLUMN_VECTOR", 13)) {
976  flags |= GRN_OBJ_COLUMN_VECTOR;
977  nptr += 13;
978  } else if (!memcmp(nptr, "COLUMN_INDEX", 12)) {
979  flags |= GRN_OBJ_COLUMN_INDEX;
980  nptr += 12;
981  } else if (!memcmp(nptr, "WITH_SECTION", 12)) {
982  flags |= GRN_OBJ_WITH_SECTION;
983  nptr += 12;
984  } else if (!memcmp(nptr, "WITH_WEIGHT", 11)) {
985  flags |= GRN_OBJ_WITH_WEIGHT;
986  nptr += 11;
987  } else if (!memcmp(nptr, "WITH_POSITION", 13)) {
988  flags |= GRN_OBJ_WITH_POSITION;
989  nptr += 13;
990  } else if (!memcmp(nptr, "RING_BUFFER", 11)) {
991  flags |= GRN_OBJ_RING_BUFFER;
992  nptr += 11;
993  } else {
994  ERR(GRN_INVALID_ARGUMENT, "invalid flags option: %.*s",
995  (int)(end - nptr), nptr);
996  return 0;
997  }
998  }
999  return flags;
1000 }
1001 
1002 static void
1003 grn_table_create_flags_to_text(grn_ctx *ctx, grn_obj *buf, grn_obj_flags flags)
1004 {
1005  GRN_BULK_REWIND(buf);
1006  switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
1008  GRN_TEXT_PUTS(ctx, buf, "TABLE_HASH_KEY");
1009  break;
1010  case GRN_OBJ_TABLE_PAT_KEY:
1011  GRN_TEXT_PUTS(ctx, buf, "TABLE_PAT_KEY");
1012  break;
1013  case GRN_OBJ_TABLE_DAT_KEY:
1014  GRN_TEXT_PUTS(ctx, buf, "TABLE_DAT_KEY");
1015  break;
1016  case GRN_OBJ_TABLE_NO_KEY:
1017  GRN_TEXT_PUTS(ctx, buf, "TABLE_NO_KEY");
1018  break;
1019  }
1020  if (flags & GRN_OBJ_KEY_WITH_SIS) {
1021  GRN_TEXT_PUTS(ctx, buf, "|KEY_WITH_SIS");
1022  }
1023  if (flags & GRN_OBJ_KEY_NORMALIZE) {
1024  GRN_TEXT_PUTS(ctx, buf, "|KEY_NORMALIZE");
1025  }
1026  if (flags & GRN_OBJ_PERSISTENT) {
1027  GRN_TEXT_PUTS(ctx, buf, "|PERSISTENT");
1028  }
1029 }
1030 
1031 static void
1032 grn_column_create_flags_to_text(grn_ctx *ctx, grn_obj *buf, grn_obj_flags flags)
1033 {
1034  GRN_BULK_REWIND(buf);
1035  switch (flags & GRN_OBJ_COLUMN_TYPE_MASK) {
1036  case GRN_OBJ_COLUMN_SCALAR:
1037  GRN_TEXT_PUTS(ctx, buf, "COLUMN_SCALAR");
1038  break;
1039  case GRN_OBJ_COLUMN_VECTOR:
1040  GRN_TEXT_PUTS(ctx, buf, "COLUMN_VECTOR");
1041  break;
1042  case GRN_OBJ_COLUMN_INDEX:
1043  GRN_TEXT_PUTS(ctx, buf, "COLUMN_INDEX");
1044  if (flags & GRN_OBJ_WITH_SECTION) {
1045  GRN_TEXT_PUTS(ctx, buf, "|WITH_SECTION");
1046  }
1047  if (flags & GRN_OBJ_WITH_WEIGHT) {
1048  GRN_TEXT_PUTS(ctx, buf, "|WITH_WEIGHT");
1049  }
1050  if (flags & GRN_OBJ_WITH_POSITION) {
1051  GRN_TEXT_PUTS(ctx, buf, "|WITH_POSITION");
1052  }
1053  break;
1054  }
1055  switch (flags & GRN_OBJ_COMPRESS_MASK) {
1056  case GRN_OBJ_COMPRESS_NONE:
1057  break;
1058  case GRN_OBJ_COMPRESS_ZLIB:
1059  GRN_TEXT_PUTS(ctx, buf, "|COMPRESS_ZLIB");
1060  break;
1061  case GRN_OBJ_COMPRESS_LZO:
1062  GRN_TEXT_PUTS(ctx, buf, "|COMPRESS_LZO");
1063  break;
1064  }
1065  if (flags & GRN_OBJ_PERSISTENT) {
1066  GRN_TEXT_PUTS(ctx, buf, "|PERSISTENT");
1067  }
1068 }
1069 
1070 static grn_obj *
1071 proc_table_create(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1072 {
1073  grn_obj *table;
1074  const char *rest;
1076  GRN_BULK_CURR(VAR(1)), &rest);
1077  if (GRN_TEXT_VALUE(VAR(1)) == rest) {
1078  flags = grn_parse_table_create_flags(ctx, GRN_TEXT_VALUE(VAR(1)),
1079  GRN_BULK_CURR(VAR(1)));
1080  if (ctx->rc) { goto exit; }
1081  }
1082  if (GRN_TEXT_LEN(VAR(0))) {
1083  grn_obj *key_type = NULL, *value_type = NULL;
1084  if (GRN_TEXT_LEN(VAR(2)) > 0) {
1085  key_type = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(2)),
1086  GRN_TEXT_LEN(VAR(2)));
1087  if (!key_type) {
1089  "[table][create] key type doesn't exist: <%.*s> (%.*s)",
1090  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)),
1091  (int)GRN_TEXT_LEN(VAR(2)), GRN_TEXT_VALUE(VAR(2)));
1092  return NULL;
1093  }
1094  }
1095  if (GRN_TEXT_LEN(VAR(3)) > 0) {
1096  value_type = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(3)),
1097  GRN_TEXT_LEN(VAR(3)));
1098  if (!value_type) {
1100  "[table][create] value type doesn't exist: <%.*s> (%.*s)",
1101  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)),
1102  (int)GRN_TEXT_LEN(VAR(3)), GRN_TEXT_VALUE(VAR(3)));
1103  return NULL;
1104  }
1105  }
1106  flags |= GRN_OBJ_PERSISTENT;
1107  table = grn_table_create(ctx,
1108  GRN_TEXT_VALUE(VAR(0)),
1109  GRN_TEXT_LEN(VAR(0)),
1110  NULL, flags,
1111  key_type,
1112  value_type);
1113  if (table) {
1114  grn_obj *normalizer_name;
1115  grn_obj_set_info(ctx, table,
1117  grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(4)),
1118  GRN_TEXT_LEN(VAR(4))));
1119  normalizer_name = VAR(5);
1120  if (GRN_TEXT_LEN(normalizer_name) > 0) {
1121  grn_obj_set_info(ctx, table,
1123  grn_ctx_get(ctx,
1124  GRN_TEXT_VALUE(normalizer_name),
1125  GRN_TEXT_LEN(normalizer_name)));
1126  }
1127  grn_obj_unlink(ctx, table);
1128  }
1129  } else {
1131  "[table][create] should not create anonymous table");
1132  }
1133 exit:
1134  GRN_OUTPUT_BOOL(!ctx->rc);
1135  return NULL;
1136 }
1137 
1138 static grn_obj *
1139 proc_table_remove(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1140 {
1141  grn_obj *table;
1142  table = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)),
1143  GRN_TEXT_LEN(VAR(0)));
1144  if (table) {
1145  grn_obj_remove(ctx,table);
1146  } else {
1147  ERR(GRN_INVALID_ARGUMENT, "table not found.");
1148  }
1149  GRN_OUTPUT_BOOL(!ctx->rc);
1150  return NULL;
1151 }
1152 
1153 static grn_obj *
1154 proc_table_rename(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1155 {
1156  grn_rc rc = GRN_SUCCESS;
1157  grn_obj *table = NULL;
1158  if (GRN_TEXT_LEN(VAR(0)) == 0) {
1159  rc = GRN_INVALID_ARGUMENT;
1160  ERR(rc, "[table][rename] table name isn't specified");
1161  goto exit;
1162  }
1163  table = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)));
1164  if (!table) {
1165  rc = GRN_INVALID_ARGUMENT;
1166  ERR(rc,
1167  "[table][rename] table isn't found: <%.*s>",
1168  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
1169  goto exit;
1170  }
1171  if (GRN_TEXT_LEN(VAR(1)) == 0) {
1172  rc = GRN_INVALID_ARGUMENT;
1173  ERR(rc,
1174  "[table][rename] new table name isn't specified: <%.*s>",
1175  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
1176  goto exit;
1177  }
1178  rc = grn_table_rename(ctx, table,
1179  GRN_TEXT_VALUE(VAR(1)), GRN_TEXT_LEN(VAR(1)));
1180  if (rc != GRN_SUCCESS && ctx->rc == GRN_SUCCESS) {
1181  ERR(rc,
1182  "[table][rename] failed to rename: <%.*s> -> <%.*s>",
1183  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)),
1184  (int)GRN_TEXT_LEN(VAR(1)), GRN_TEXT_VALUE(VAR(1)));
1185  }
1186 exit:
1187  GRN_OUTPUT_BOOL(!rc);
1188  if (table) { grn_obj_unlink(ctx, table); }
1189  return NULL;
1190 }
1191 
1192 static grn_obj *
1193 proc_column_create(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1194 {
1195  grn_obj *column, *table = NULL, *type = NULL;
1196  const char *rest;
1198  GRN_BULK_CURR(VAR(2)), &rest);
1199  if (GRN_TEXT_VALUE(VAR(2)) == rest) {
1200  flags = grn_parse_column_create_flags(ctx, GRN_TEXT_VALUE(VAR(2)),
1201  GRN_BULK_CURR(VAR(2)));
1202  if (ctx->rc) { goto exit; }
1203  }
1204  table = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)));
1205  if (!table) {
1207  "[column][create] table doesn't exist: <%.*s>",
1208  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
1209  goto exit;
1210  }
1211  type = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(3)),
1212  GRN_TEXT_LEN(VAR(3)));
1213  if (!type) {
1215  "[column][create] type doesn't exist: <%.*s>",
1216  (int)GRN_TEXT_LEN(VAR(3)), GRN_TEXT_VALUE(VAR(3))) ;
1217  goto exit;
1218  }
1219  if (GRN_TEXT_LEN(VAR(1))) {
1220  flags |= GRN_OBJ_PERSISTENT;
1221  } else {
1222  ERR(GRN_INVALID_ARGUMENT, "[column][create] name is missing");
1223  goto exit;
1224  }
1225  column = grn_column_create(ctx, table,
1226  GRN_TEXT_VALUE(VAR(1)),
1227  GRN_TEXT_LEN(VAR(1)),
1228  NULL, flags, type);
1229  if (column) {
1230  if (GRN_TEXT_LEN(VAR(4))) {
1231  grn_obj sources, source_ids, **p, **pe;
1233  GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
1234  grn_obj_columns(ctx, type,
1235  GRN_TEXT_VALUE(VAR(4)),
1236  GRN_TEXT_LEN(VAR(4)),
1237  &sources);
1238  p = (grn_obj **)GRN_BULK_HEAD(&sources);
1239  pe = (grn_obj **)GRN_BULK_CURR(&sources);
1240  for (; p < pe; p++) {
1241  grn_id source_id = grn_obj_id(ctx, *p);
1242  if ((*p)->header.type == GRN_ACCESSOR) {
1243  /* todo : if "_key" assigned */
1244  source_id = grn_obj_id(ctx, type);
1245  }
1246  if (source_id) {
1247  GRN_UINT32_PUT(ctx, &source_ids, source_id);
1248  }
1249  grn_obj_unlink(ctx, *p);
1250  }
1251  if (GRN_BULK_VSIZE(&source_ids)) {
1252  grn_obj_set_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
1253  }
1254  GRN_OBJ_FIN(ctx, &source_ids);
1255  GRN_OBJ_FIN(ctx, &sources);
1256  }
1257  grn_obj_unlink(ctx, column);
1258  }
1259 exit:
1260  GRN_OUTPUT_BOOL(!ctx->rc);
1261  if (table) { grn_obj_unlink(ctx, table); }
1262  if (type) { grn_obj_unlink(ctx, type); }
1263  return NULL;
1264 }
1265 
1266 static grn_obj *
1267 proc_column_remove(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1268 {
1269  grn_obj *table, *col;
1270  char *colname,fullname[GRN_TABLE_MAX_KEY_SIZE];
1271  unsigned int colname_len,fullname_len;
1272 
1273  table = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)),
1274  GRN_TEXT_LEN(VAR(0)));
1275 
1276  colname = GRN_TEXT_VALUE(VAR(1));
1277  colname_len = GRN_TEXT_LEN(VAR(1));
1278 
1279  if ((fullname_len = grn_obj_name(ctx, table, fullname, GRN_TABLE_MAX_KEY_SIZE))) {
1280  fullname[fullname_len] = GRN_DB_DELIMITER;
1281  memcpy((fullname + fullname_len + 1), colname, colname_len);
1282  fullname_len += colname_len + 1;
1283  //TODO:check fullname_len < GRN_TABLE_MAX_KEY_SIZE
1284  col = grn_ctx_get(ctx, fullname, fullname_len);
1285  if (col) {
1286  grn_obj_remove(ctx, col);
1287  } else {
1288  ERR(GRN_INVALID_ARGUMENT, "column not found.");
1289  }
1290  } else {
1291  ERR(GRN_INVALID_ARGUMENT, "table not found.");
1292  }
1293  GRN_OUTPUT_BOOL(!ctx->rc);
1294  return NULL;
1295 }
1296 
1297 static grn_obj *
1298 proc_column_rename(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1299 {
1300  grn_rc rc = GRN_SUCCESS;
1301  grn_obj *table = NULL;
1302  grn_obj *column = NULL;
1303  if (GRN_TEXT_LEN(VAR(0)) == 0) {
1304  rc = GRN_INVALID_ARGUMENT;
1305  ERR(rc, "[column][rename] table name isn't specified");
1306  goto exit;
1307  }
1308  table = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)));
1309  if (!table) {
1310  rc = GRN_INVALID_ARGUMENT;
1311  ERR(rc,
1312  "[column][rename] table isn't found: <%.*s>",
1313  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
1314  goto exit;
1315  }
1316  if (GRN_TEXT_LEN(VAR(1)) == 0) {
1317  rc = GRN_INVALID_ARGUMENT;
1318  ERR(rc,
1319  "[column][rename] column name isn't specified: <%.*s>",
1320  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
1321  goto exit;
1322  }
1323  column = grn_obj_column(ctx, table,
1324  GRN_TEXT_VALUE(VAR(1)), GRN_TEXT_LEN(VAR(1)));
1325  if (!column) {
1326  rc = GRN_INVALID_ARGUMENT;
1327  ERR(rc,
1328  "[column][rename] column isn't found: <%.*s.%.*s>",
1329  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)),
1330  (int)GRN_TEXT_LEN(VAR(1)), GRN_TEXT_VALUE(VAR(1)));
1331  goto exit;
1332  }
1333  if (GRN_TEXT_LEN(VAR(2)) == 0) {
1334  rc = GRN_INVALID_ARGUMENT;
1335  ERR(rc,
1336  "[column][rename] new column name isn't specified: <%.*s.%.*s>",
1337  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)),
1338  (int)GRN_TEXT_LEN(VAR(1)), GRN_TEXT_VALUE(VAR(1)));
1339  goto exit;
1340  }
1341  rc = grn_column_rename(ctx, column,
1342  GRN_TEXT_VALUE(VAR(2)), GRN_TEXT_LEN(VAR(2)));
1343  if (rc != GRN_SUCCESS && ctx->rc == GRN_SUCCESS) {
1344  ERR(rc,
1345  "[column][rename] failed to rename: <%.*s.%.*s> -> <%.*s.%.*s>",
1346  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)),
1347  (int)GRN_TEXT_LEN(VAR(1)), GRN_TEXT_VALUE(VAR(1)),
1348  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)),
1349  (int)GRN_TEXT_LEN(VAR(2)), GRN_TEXT_VALUE(VAR(2)));
1350  }
1351 exit:
1352  GRN_OUTPUT_BOOL(!rc);
1353  if (column) { grn_obj_unlink(ctx, column); }
1354  if (table) { grn_obj_unlink(ctx, table); }
1355  return NULL;
1356 }
1357 
1358 #define GRN_STRLEN(s) ((s) ? strlen(s) : 0)
1359 
1360 static void
1361 output_column_name(grn_ctx *ctx, grn_obj *column)
1362 {
1363  grn_obj bulk;
1364  int name_len;
1365  char name[GRN_TABLE_MAX_KEY_SIZE];
1366 
1368  name_len = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
1369  GRN_TEXT_SET(ctx, &bulk, name, name_len);
1370 
1371  GRN_OUTPUT_OBJ(&bulk, NULL);
1372  GRN_OBJ_FIN(ctx, &bulk);
1373 }
1374 
1375 static void
1376 output_object_name(grn_ctx *ctx, grn_obj *obj)
1377 {
1378  grn_obj bulk;
1379  int name_len;
1380  char name[GRN_TABLE_MAX_KEY_SIZE];
1381 
1382  if (obj) {
1384  name_len = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
1385  GRN_TEXT_SET(ctx, &bulk, name, name_len);
1386  } else {
1387  GRN_VOID_INIT(&bulk);
1388  }
1389 
1390  GRN_OUTPUT_OBJ(&bulk, NULL);
1391  GRN_OBJ_FIN(ctx, &bulk);
1392 }
1393 
1394 static void
1395 output_object_id_name(grn_ctx *ctx, grn_id id)
1396 {
1397  grn_obj *obj = NULL;
1398 
1399  if (id != GRN_ID_NIL) {
1400  obj = grn_ctx_at(ctx, id);
1401  }
1402 
1403  output_object_name(ctx, obj);
1404 }
1405 
1406 static int
1407 output_column_info(grn_ctx *ctx, grn_obj *column)
1408 {
1409  grn_obj o;
1410  grn_id id;
1411  const char *type;
1412  const char *path;
1413 
1414  switch (column->header.type) {
1415  case GRN_COLUMN_FIX_SIZE:
1416  type = "fix";
1417  break;
1418  case GRN_COLUMN_VAR_SIZE:
1419  type = "var";
1420  break;
1421  case GRN_COLUMN_INDEX:
1422  type = "index";
1423  break;
1424  default:
1425  GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid header type %d\n", column->header.type);
1426  return 0;
1427  }
1428  id = grn_obj_id(ctx, column);
1429  path = grn_obj_path(ctx, column);
1430  GRN_TEXT_INIT(&o, 0);
1431  GRN_OUTPUT_ARRAY_OPEN("COLUMN", 8);
1432  GRN_OUTPUT_INT64(id);
1433  output_column_name(ctx, column);
1434  GRN_OUTPUT_CSTR(path);
1435  GRN_OUTPUT_CSTR(type);
1436  grn_column_create_flags_to_text(ctx, &o, column->header.flags);
1437  GRN_OUTPUT_OBJ(&o, NULL);
1438  output_object_id_name(ctx, column->header.domain);
1439  output_object_id_name(ctx, grn_obj_get_range(ctx, column));
1440  {
1441  grn_db_obj *obj = (grn_db_obj *)column;
1442  grn_id *s = obj->source;
1443  int i = 0, n = obj->source_size / sizeof(grn_id);
1444  GRN_OUTPUT_ARRAY_OPEN("SOURCES", n);
1445  for (i = 0; i < n; i++, s++) {
1446  output_object_id_name(ctx, *s);
1447  }
1449 
1450  }
1451  // output_obj_source(ctx, (grn_db_obj *)column);
1453  GRN_OBJ_FIN(ctx, &o);
1454  return 1;
1455 }
1456 
1457 static grn_obj *
1458 proc_column_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1459 {
1460  grn_obj *table;
1461  if ((table = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)),
1462  GRN_TEXT_LEN(VAR(0))))) {
1463  grn_hash *cols;
1464  grn_obj *col;
1465  int column_list_size = -1;
1466 #ifdef GRN_WITH_MESSAGE_PACK
1467  column_list_size = 1; /* [header, (key), (COLUMNS)] */
1468  if ((col = grn_obj_column(ctx, table, KEY_NAME, sizeof(KEY_NAME)-1))) {
1469  column_list_size++;
1470  grn_obj_unlink(ctx, col);
1471  }
1472  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1474  column_list_size += grn_table_columns(ctx, table, NULL, 0,
1475  (grn_obj *)cols);
1476  grn_hash_close(ctx, cols);
1477  }
1478 #endif
1479  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1481  GRN_OUTPUT_ARRAY_OPEN("COLUMN_LIST", column_list_size);
1482  GRN_OUTPUT_ARRAY_OPEN("HEADER", 8);
1483  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1484  GRN_OUTPUT_CSTR("id");
1485  GRN_OUTPUT_CSTR("UInt32");
1487  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1488  GRN_OUTPUT_CSTR("name");
1489  GRN_OUTPUT_CSTR("ShortText");
1491  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1492  GRN_OUTPUT_CSTR("path");
1493  GRN_OUTPUT_CSTR("ShortText");
1495  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1496  GRN_OUTPUT_CSTR("type");
1497  GRN_OUTPUT_CSTR("ShortText");
1499  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1500  GRN_OUTPUT_CSTR("flags");
1501  GRN_OUTPUT_CSTR("ShortText");
1503  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1504  GRN_OUTPUT_CSTR("domain");
1505  GRN_OUTPUT_CSTR("ShortText");
1507  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1508  GRN_OUTPUT_CSTR("range");
1509  GRN_OUTPUT_CSTR("ShortText");
1511  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1512  GRN_OUTPUT_CSTR("source");
1513  GRN_OUTPUT_CSTR("ShortText");
1516  if ((col = grn_obj_column(ctx, table, KEY_NAME, sizeof(KEY_NAME)-1))) {
1517  int name_len;
1518  char name_buf[GRN_TABLE_MAX_KEY_SIZE];
1519  grn_id id;
1520  grn_obj buf;
1521  GRN_TEXT_INIT(&buf, 0);
1522  GRN_OUTPUT_ARRAY_OPEN("COLUMN", 8);
1523  id = grn_obj_id(ctx, table);
1524  GRN_OUTPUT_INT64(id);
1526  GRN_OUTPUT_CSTR("");
1527  GRN_OUTPUT_CSTR("");
1528  grn_column_create_flags_to_text(ctx, &buf, 0);
1529  GRN_OUTPUT_OBJ(&buf, NULL);
1530  name_len = grn_obj_name(ctx, table, name_buf, GRN_TABLE_MAX_KEY_SIZE);
1531  GRN_OUTPUT_STR(name_buf, name_len);
1532  output_object_id_name(ctx, table->header.domain);
1533  GRN_OUTPUT_ARRAY_OPEN("SOURCES", 0);
1536  GRN_OBJ_FIN(ctx, &buf);
1537  grn_obj_unlink(ctx, col);
1538  }
1539  if (grn_table_columns(ctx, table, NULL, 0, (grn_obj *)cols) >= 0) {
1540  grn_id *key;
1541  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
1542  if ((col = grn_ctx_at(ctx, *key))) {
1543  output_column_info(ctx, col);
1544  grn_obj_unlink(ctx, col);
1545  }
1546  });
1547  }
1549  grn_hash_close(ctx, cols);
1550  }
1551  grn_obj_unlink(ctx, table);
1552  } else {
1553  ERR(GRN_INVALID_ARGUMENT, "table '%.*s' does not exist.",
1554  (int)GRN_TEXT_LEN(VAR(0)),
1555  GRN_TEXT_VALUE(VAR(0)));
1556  }
1557  return NULL;
1558 }
1559 
1560 static grn_bool
1561 is_table(grn_obj *obj)
1562 {
1563  switch (obj->header.type) {
1564  case GRN_TABLE_HASH_KEY:
1565  case GRN_TABLE_PAT_KEY:
1566  case GRN_TABLE_DAT_KEY:
1567  case GRN_TABLE_NO_KEY:
1568  return GRN_TRUE;
1569  default:
1570  return GRN_FALSE;
1571  }
1572 }
1573 
1574 static int
1575 output_table_info(grn_ctx *ctx, grn_obj *table)
1576 {
1577  grn_id id;
1578  grn_obj o;
1579  const char *path;
1580  grn_obj *default_tokenizer;
1581  grn_obj *normalizer;
1582 
1583  id = grn_obj_id(ctx, table);
1584  path = grn_obj_path(ctx, table);
1585  GRN_TEXT_INIT(&o, 0);
1586  GRN_OUTPUT_ARRAY_OPEN("TABLE", 8);
1587  GRN_OUTPUT_INT64(id);
1588  output_object_id_name(ctx, id);
1589  GRN_OUTPUT_CSTR(path);
1590  grn_table_create_flags_to_text(ctx, &o, table->header.flags);
1591  GRN_OUTPUT_OBJ(&o, NULL);
1592  output_object_id_name(ctx, table->header.domain);
1593  output_object_id_name(ctx, grn_obj_get_range(ctx, table));
1594  default_tokenizer = grn_obj_get_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER,
1595  NULL);
1596  output_object_name(ctx, default_tokenizer);
1597  normalizer = grn_obj_get_info(ctx, table, GRN_INFO_NORMALIZER, NULL);
1598  output_object_name(ctx, normalizer);
1599  grn_obj_unlink(ctx, normalizer);
1601  GRN_OBJ_FIN(ctx, &o);
1602  return 1;
1603 }
1604 
1605 static grn_obj *
1606 proc_table_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1607 {
1608  grn_table_cursor *cur;
1609  grn_obj tables;
1610  int n_top_level_elements;
1611  int n_elements_for_header = 1;
1612  int n_tables;
1613  int i;
1614 
1616 
1617  if ((cur = grn_table_cursor_open(ctx, ctx->impl->db, NULL, 0, NULL, 0, 0, -1, 0))) {
1618  grn_id id;
1619  while ((id = grn_table_cursor_next(ctx, cur)) != GRN_ID_NIL) {
1620  grn_obj *object;
1621  if ((object = grn_ctx_at(ctx, id))) {
1622  if (is_table(object)) {
1623  GRN_PTR_PUT(ctx, &tables, object);
1624  } else {
1625  grn_obj_unlink(ctx, object);
1626  }
1627  } else {
1628  if (ctx->rc != GRN_SUCCESS) {
1629  ERRCLR(ctx);
1630  }
1631  }
1632  }
1633  grn_table_cursor_close(ctx, cur);
1634  }
1635 
1636  n_tables = GRN_BULK_VSIZE(&tables) / sizeof(grn_obj *);
1637  n_top_level_elements = n_elements_for_header + n_tables;
1638  GRN_OUTPUT_ARRAY_OPEN("TABLE_LIST", n_top_level_elements);
1639 
1640  GRN_OUTPUT_ARRAY_OPEN("HEADER", 8);
1641  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1642  GRN_OUTPUT_CSTR("id");
1643  GRN_OUTPUT_CSTR("UInt32");
1645  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1646  GRN_OUTPUT_CSTR("name");
1647  GRN_OUTPUT_CSTR("ShortText");
1649  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1650  GRN_OUTPUT_CSTR("path");
1651  GRN_OUTPUT_CSTR("ShortText");
1653  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1654  GRN_OUTPUT_CSTR("flags");
1655  GRN_OUTPUT_CSTR("ShortText");
1657  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1658  GRN_OUTPUT_CSTR("domain");
1659  GRN_OUTPUT_CSTR("ShortText");
1661  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1662  GRN_OUTPUT_CSTR("range");
1663  GRN_OUTPUT_CSTR("ShortText");
1665  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1666  GRN_OUTPUT_CSTR("default_tokenizer");
1667  GRN_OUTPUT_CSTR("ShortText");
1669  GRN_OUTPUT_ARRAY_OPEN("PROPERTY", 2);
1670  GRN_OUTPUT_CSTR("normalizer");
1671  GRN_OUTPUT_CSTR("ShortText");
1674 
1675  for (i = 0; i < n_tables; i++) {
1676  grn_obj *table = ((grn_obj **)GRN_BULK_HEAD(&tables))[i];
1677  output_table_info(ctx, table);
1678  grn_obj_unlink(ctx, table);
1679  }
1680  GRN_OBJ_FIN(ctx, &tables);
1681 
1683 
1684  return NULL;
1685 }
1686 
1687 static grn_obj *
1688 proc_missing(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1689 {
1690  uint32_t plen;
1691  grn_obj *outbuf = ctx->impl->outbuf;
1692  static int grn_document_root_len = -1;
1693  if (!grn_document_root) { return NULL; }
1694  if (grn_document_root_len < 0) {
1695  size_t l;
1696  if ((l = strlen(grn_document_root)) > PATH_MAX) {
1697  return NULL;
1698  }
1699  grn_document_root_len = (int)l;
1700  if (l > 0 && grn_document_root[l - 1] == '/') { grn_document_root_len--; }
1701  }
1702  if ((plen = GRN_TEXT_LEN(VAR(0))) + grn_document_root_len < PATH_MAX) {
1703  char path[PATH_MAX];
1704  memcpy(path, grn_document_root, grn_document_root_len);
1705  path[grn_document_root_len] = '/';
1707  GRN_TEXT_VALUE(VAR(0)),
1708  GRN_TEXT_LEN(VAR(0)),
1709  path + grn_document_root_len + 1,
1710  PATH_MAX - grn_document_root_len - 1);
1711  grn_bulk_put_from_file(ctx, outbuf, path);
1712  } else {
1713  uint32_t abbrlen = 32;
1715  "too long path name: <%s/%.*s...> %u(%u)",
1717  abbrlen < plen ? abbrlen : plen, GRN_TEXT_VALUE(VAR(0)),
1718  plen + grn_document_root_len, PATH_MAX);
1719  }
1720  return NULL;
1721 }
1722 
1723 static grn_obj *
1724 proc_quit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1725 {
1726  ctx->stat = GRN_CTX_QUITTING;
1727  GRN_OUTPUT_BOOL(!ctx->rc);
1728  return NULL;
1729 }
1730 
1731 static grn_obj *
1732 proc_shutdown(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1733 {
1735  ctx->stat = GRN_CTX_QUITTING;
1736  GRN_OUTPUT_BOOL(!ctx->rc);
1737  return NULL;
1738 }
1739 
1740 static grn_obj *
1741 proc_clearlock(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1742 {
1743  int target_name_len;
1744  grn_obj *target_name;
1745  grn_obj *obj;
1746 
1747  target_name = VAR(0);
1748  target_name_len = GRN_TEXT_LEN(target_name);
1749 
1750  if (target_name_len) {
1751  obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(target_name), target_name_len);
1752  } else {
1753  obj = ctx->impl->db;
1754  }
1755 
1756  if (obj) {
1757  grn_obj_clear_lock(ctx, obj);
1758  } else {
1759  ERR(GRN_INVALID_ARGUMENT, "[clearlock] target object not found: <%.*s>",
1760  target_name_len, GRN_TEXT_VALUE(target_name));
1761  }
1762  GRN_OUTPUT_BOOL(!ctx->rc);
1763  return NULL;
1764 }
1765 
1766 static grn_obj *
1767 proc_defrag(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1768 {
1769  grn_obj *obj;
1770  int olen, threshold;
1771  olen = GRN_TEXT_LEN(VAR(0));
1772 
1773  if (olen) {
1774  obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), olen);
1775  } else {
1776  obj = ctx->impl->db;
1777  }
1778 
1779  threshold = GRN_TEXT_LEN(VAR(1))
1780  ? grn_atoi(GRN_TEXT_VALUE(VAR(1)), GRN_BULK_CURR(VAR(1)), NULL)
1781  : 0;
1782 
1783  if (obj) {
1784  grn_obj_defrag(ctx, obj, threshold);
1785  } else {
1786  ERR(GRN_INVALID_ARGUMENT, "defrag object not found");
1787  }
1788  GRN_OUTPUT_BOOL(!ctx->rc);
1789  return NULL;
1790 }
1791 
1792 static char slev[] = " EACewnid-";
1793 
1794 static grn_obj *
1795 proc_log_level(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1796 {
1797  char *p;
1798  if (GRN_TEXT_LEN(VAR(0)) &&
1799  (p = strchr(slev, GRN_TEXT_VALUE(VAR(0))[0]))) {
1800  grn_log_level max_level = (grn_log_level)(p - slev);
1801  grn_logger_set_max_level(ctx, max_level);
1802  } else {
1803  ERR(GRN_INVALID_ARGUMENT, "invalid log level.");
1804  }
1805  GRN_OUTPUT_BOOL(!ctx->rc);
1806  return NULL;
1807 }
1808 
1809 static grn_obj *
1810 proc_log_put(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1811 {
1812  char *p;
1813  if (GRN_TEXT_LEN(VAR(0)) &&
1814  (p = strchr(slev, GRN_TEXT_VALUE(VAR(0))[0]))) {
1815  GRN_TEXT_PUTC(ctx, VAR(1), '\0');
1816  GRN_LOG(ctx, (int)(p - slev), "%s", GRN_TEXT_VALUE(VAR(1)));
1817  } else {
1818  ERR(GRN_INVALID_ARGUMENT, "invalid log level.");
1819  }
1820  GRN_OUTPUT_BOOL(!ctx->rc);
1821  return NULL;
1822 }
1823 
1824 static grn_obj *
1825 proc_log_reopen(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1826 {
1827  grn_log_reopen(ctx);
1828  GRN_OUTPUT_BOOL(!ctx->rc);
1829  return NULL;
1830 }
1831 
1832 static grn_rc
1833 proc_delete_validate_selector(grn_ctx *ctx, grn_obj *table, grn_obj *table_name,
1834  grn_obj *key, grn_obj *id, grn_obj *filter)
1835 {
1836  grn_rc rc = GRN_SUCCESS;
1837 
1838  if (!table) {
1839  rc = GRN_INVALID_ARGUMENT;
1840  ERR(rc,
1841  "[table][record][delete] table doesn't exist: <%.*s>",
1842  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
1843  return rc;
1844  }
1845 
1846  if (GRN_TEXT_LEN(key) == 0 &&
1847  GRN_TEXT_LEN(id) == 0 &&
1848  GRN_TEXT_LEN(filter) == 0) {
1849  rc = GRN_INVALID_ARGUMENT;
1850  ERR(rc,
1851  "[table][record][delete] either key, id or filter must be specified: "
1852  "table: <%.*s>",
1853  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
1854  return rc;
1855  }
1856 
1857  if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
1858  rc = GRN_INVALID_ARGUMENT;
1859  ERR(rc,
1860  "[table][record][delete] "
1861  "record selector must be one of key, id and filter: "
1862  "table: <%.*s>, key: <%.*s>, id: <%.*s>, filter: <%.*s>",
1863  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
1864  (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
1865  (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
1866  (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
1867  return rc;
1868  }
1869 
1870  if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter) == 0) {
1871  rc = GRN_INVALID_ARGUMENT;
1872  ERR(rc,
1873  "[table][record][delete] "
1874  "can't use both key and id: table: <%.*s>, key: <%.*s>, id: <%.*s>",
1875  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
1876  (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
1877  (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id));
1878  return rc;
1879  }
1880 
1881  if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) == 0 && GRN_TEXT_LEN(filter)) {
1882  rc = GRN_INVALID_ARGUMENT;
1883  ERR(rc,
1884  "[table][record][delete] "
1885  "can't use both key and filter: "
1886  "table: <%.*s>, key: <%.*s>, filter: <%.*s>",
1887  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
1888  (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
1889  (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
1890  return rc;
1891  }
1892 
1893  if (GRN_TEXT_LEN(key) == 0 && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
1894  rc = GRN_INVALID_ARGUMENT;
1895  ERR(rc,
1896  "[table][record][delete] "
1897  "can't use both id and filter: "
1898  "table: <%.*s>, id: <%.*s>, filter: <%.*s>",
1899  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
1900  (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
1901  (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
1902  return rc;
1903  }
1904 
1905  return rc;
1906 }
1907 
1908 static grn_obj *
1909 proc_delete(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1910 {
1912  grn_obj *table_name = VAR(0);
1913  grn_obj *key = VAR(1);
1914  grn_obj *id = VAR(2);
1915  grn_obj *filter = VAR(3);
1916  grn_obj *table = NULL;
1917 
1918  if (GRN_TEXT_LEN(table_name) == 0) {
1919  rc = GRN_INVALID_ARGUMENT;
1920  ERR(rc, "[table][record][delete] table name isn't specified");
1921  goto exit;
1922  }
1923 
1924  table = grn_ctx_get(ctx,
1925  GRN_TEXT_VALUE(table_name),
1926  GRN_TEXT_LEN(table_name));
1927  rc = proc_delete_validate_selector(ctx, table, table_name, key, id, filter);
1928  if (rc != GRN_SUCCESS) { goto exit; }
1929 
1930  if (GRN_TEXT_LEN(key)) {
1931  grn_obj casted_key;
1932  if (key->header.domain != table->header.domain) {
1933  GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain);
1934  grn_obj_cast(ctx, key, &casted_key, GRN_FALSE);
1935  key = &casted_key;
1936  }
1937  if (ctx->rc) {
1938  rc = ctx->rc;
1939  } else {
1940  rc = grn_table_delete(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key));
1941  if (key == &casted_key) {
1942  GRN_OBJ_FIN(ctx, &casted_key);
1943  }
1944  }
1945  } else if (GRN_TEXT_LEN(id)) {
1946  const char *end;
1947  grn_id parsed_id = grn_atoui(GRN_TEXT_VALUE(id), GRN_BULK_CURR(id), &end);
1948  if (end == GRN_BULK_CURR(id)) {
1949  rc = grn_table_delete_by_id(ctx, table, parsed_id);
1950  } else {
1951  rc = GRN_INVALID_ARGUMENT;
1952  ERR(rc,
1953  "[table][record][delete] id should be number: "
1954  "table: <%.*s>, id: <%.*s>, detail: <%.*s|%c|%.*s>",
1955  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
1956  (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
1957  (int)(end - GRN_TEXT_VALUE(id)), GRN_TEXT_VALUE(id),
1958  end[0],
1959  (int)(GRN_TEXT_VALUE(id) - end - 1), end + 1);
1960  }
1961  } else if (GRN_TEXT_LEN(filter)) {
1962  grn_obj *cond, *v;
1963 
1964  GRN_EXPR_CREATE_FOR_QUERY(ctx, table, cond, v);
1965  grn_expr_parse(ctx, cond,
1966  GRN_TEXT_VALUE(filter),
1967  GRN_TEXT_LEN(filter),
1968  NULL, GRN_OP_MATCH, GRN_OP_AND,
1970  if (ctx->rc) {
1971  char original_error_message[GRN_CTX_MSGSIZE];
1972  strcpy(original_error_message, ctx->errbuf);
1973  rc = ctx->rc;
1974  ERR(rc,
1975  "[table][record][delete] failed to parse filter: "
1976  "table: <%.*s>, filter: <%.*s>, detail: <%s>",
1977  (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
1978  (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter),
1979  original_error_message);
1980  } else {
1981  grn_obj *records;
1982 
1983  records = grn_table_select(ctx, table, cond, NULL, GRN_OP_OR);
1984  if (records) {
1985  void *key = NULL;
1986  GRN_TABLE_EACH(ctx, records, GRN_ID_NIL, GRN_ID_NIL,
1987  result_id, &key, NULL, NULL, {
1988  grn_id id = *(grn_id *)key;
1989  grn_table_delete_by_id(ctx, table, id);
1990  if (ctx->rc == GRN_OPERATION_NOT_PERMITTED) {
1991  ERRCLR(ctx);
1992  }
1993  });
1994  grn_obj_unlink(ctx, records);
1995  }
1996  }
1997  grn_obj_unlink(ctx, cond);
1998  }
1999 
2000 exit :
2001  if (table) {
2002  grn_obj_unlink(ctx, table);
2003  }
2004  GRN_OUTPUT_BOOL(!rc);
2005  return NULL;
2006 }
2007 
2008 static void
2009 dump_name(grn_ctx *ctx, grn_obj *outbuf, const char *name, int name_len)
2010 {
2011  grn_obj escaped_name;
2012  GRN_TEXT_INIT(&escaped_name, 0);
2013  grn_text_esc(ctx, &escaped_name, name, name_len);
2014  /* is no character escaped? */
2015  /* TODO false positive with spaces inside names */
2016  if (GRN_TEXT_LEN(&escaped_name) == name_len + 2) {
2017  GRN_TEXT_PUT(ctx, outbuf, name, name_len);
2018  } else {
2019  GRN_TEXT_PUT(ctx, outbuf,
2020  GRN_TEXT_VALUE(&escaped_name), GRN_TEXT_LEN(&escaped_name));
2021  }
2022  grn_obj_close(ctx, &escaped_name);
2023 }
2024 
2025 static void
2026 dump_obj_name(grn_ctx *ctx, grn_obj *outbuf, grn_obj *obj)
2027 {
2028  char name[GRN_TABLE_MAX_KEY_SIZE];
2029  int name_len;
2030  name_len = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
2031  dump_name(ctx, outbuf, name, name_len);
2032 }
2033 
2034 static void
2035 dump_column_name(grn_ctx *ctx, grn_obj *outbuf, grn_obj *column)
2036 {
2037  char name[GRN_TABLE_MAX_KEY_SIZE];
2038  int name_len;
2039  name_len = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
2040  dump_name(ctx, outbuf, name, name_len);
2041 }
2042 
2043 static void
2044 dump_index_column_sources(grn_ctx *ctx, grn_obj *outbuf, grn_obj *column)
2045 {
2046  grn_obj sources;
2047  grn_id *source_ids;
2048  int i, n;
2049 
2050  GRN_OBJ_INIT(&sources, GRN_BULK, 0, GRN_ID_NIL);
2051  grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &sources);
2052 
2053  n = GRN_BULK_VSIZE(&sources) / sizeof(grn_id);
2054  source_ids = (grn_id *)GRN_BULK_HEAD(&sources);
2055  if (n > 0) {
2056  GRN_TEXT_PUTC(ctx, outbuf, ' ');
2057  }
2058  for (i = 0; i < n; i++) {
2059  grn_obj *source;
2060  if ((source = grn_ctx_at(ctx, *source_ids))) {
2061  if (i) { GRN_TEXT_PUTC(ctx, outbuf, ','); }
2062  switch (source->header.type) {
2063  case GRN_TABLE_PAT_KEY:
2064  case GRN_TABLE_DAT_KEY:
2065  case GRN_TABLE_HASH_KEY:
2066  GRN_TEXT_PUTS(ctx, outbuf, "_key");
2067  break;
2068  default:
2069  dump_column_name(ctx, outbuf, source);
2070  break;
2071  }
2072  }
2073  source_ids++;
2074  }
2075  grn_obj_close(ctx, &sources);
2076 }
2077 
2078 static void
2079 dump_column(grn_ctx *ctx, grn_obj *outbuf , grn_obj *table, grn_obj *column)
2080 {
2081  grn_obj *type;
2082  grn_obj_flags default_flags = GRN_OBJ_PERSISTENT;
2083  grn_obj buf;
2084 
2085  type = grn_ctx_at(ctx, ((grn_db_obj *)column)->range);
2086  if (!type) {
2087  // ERR(GRN_RANGE_ERROR, "couldn't get column's type object");
2088  return;
2089  }
2090 
2091  GRN_TEXT_PUTS(ctx, outbuf, "column_create ");
2092  dump_obj_name(ctx, outbuf, table);
2093  GRN_TEXT_PUTC(ctx, outbuf, ' ');
2094  dump_column_name(ctx, outbuf, column);
2095  GRN_TEXT_PUTC(ctx, outbuf, ' ');
2096  if (type->header.type == GRN_TYPE) {
2097  default_flags |= type->header.flags;
2098  }
2099  GRN_TEXT_INIT(&buf, 0);
2100  grn_column_create_flags_to_text(ctx, &buf, column->header.flags & ~default_flags);
2101  GRN_TEXT_PUT(ctx, outbuf, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2102  GRN_OBJ_FIN(ctx, &buf);
2103  GRN_TEXT_PUTC(ctx, outbuf, ' ');
2104  dump_obj_name(ctx, outbuf, type);
2105  if (column->header.flags & GRN_OBJ_COLUMN_INDEX) {
2106  dump_index_column_sources(ctx, outbuf, column);
2107  }
2108  GRN_TEXT_PUTC(ctx, outbuf, '\n');
2109 
2110  grn_obj_unlink(ctx, type);
2111 }
2112 
2113 static int
2114 reference_column_p(grn_ctx *ctx, grn_obj *column)
2115 {
2116  grn_obj *range;
2117 
2118  range = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
2119  if (!range) {
2120  return GRN_FALSE;
2121  }
2122 
2123  switch (range->header.type) {
2124  case GRN_TABLE_HASH_KEY:
2125  case GRN_TABLE_PAT_KEY:
2126  case GRN_TABLE_DAT_KEY:
2127  case GRN_TABLE_NO_KEY:
2128  return GRN_TRUE;
2129  default:
2130  return GRN_FALSE;
2131  }
2132 }
2133 
2134 static void
2135 dump_columns(grn_ctx *ctx, grn_obj *outbuf, grn_obj *table,
2136  grn_obj *pending_columns)
2137 {
2138  grn_hash *columns;
2139  columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
2141  if (!columns) {
2142  ERR(GRN_NO_MEMORY_AVAILABLE, "couldn't create a hash to hold columns");
2143  return;
2144  }
2145 
2146  if (grn_table_columns(ctx, table, NULL, 0, (grn_obj *)columns) >= 0) {
2147  grn_id *key;
2148 
2149  GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
2150  grn_obj *column;
2151  if ((column = grn_ctx_at(ctx, *key))) {
2152  if (reference_column_p(ctx, column)) {
2153  GRN_PTR_PUT(ctx, pending_columns, column);
2154  } else {
2155  dump_column(ctx, outbuf, table, column);
2156  grn_obj_unlink(ctx, column);
2157  }
2158  }
2159  });
2160  }
2161  grn_hash_close(ctx, columns);
2162 }
2163 
2164 static void
2165 dump_records(grn_ctx *ctx, grn_obj *outbuf, grn_obj *table)
2166 {
2167  grn_obj **columns;
2168  grn_id old_id = 0, id;
2169  grn_table_cursor *cursor;
2170  int i, ncolumns, n_use_columns;
2171  grn_obj columnbuf, delete_commands, use_columns, column_name;
2172 
2173  switch (table->header.type) {
2174  case GRN_TABLE_HASH_KEY:
2175  case GRN_TABLE_PAT_KEY:
2176  case GRN_TABLE_DAT_KEY:
2177  case GRN_TABLE_NO_KEY:
2178  break;
2179  default:
2180  return;
2181  }
2182 
2183  if (grn_table_size(ctx, table) == 0) {
2184  return;
2185  }
2186 
2187  GRN_TEXT_INIT(&delete_commands, 0);
2188 
2189  GRN_TEXT_PUTS(ctx, outbuf, "load --table ");
2190  dump_obj_name(ctx, outbuf, table);
2191  GRN_TEXT_PUTS(ctx, outbuf, "\n[\n");
2192 
2193  GRN_PTR_INIT(&columnbuf, GRN_OBJ_VECTOR, GRN_ID_NIL);
2194  grn_obj_columns(ctx, table, DUMP_COLUMNS, strlen(DUMP_COLUMNS), &columnbuf);
2195  columns = (grn_obj **)GRN_BULK_HEAD(&columnbuf);
2196  ncolumns = GRN_BULK_VSIZE(&columnbuf)/sizeof(grn_obj *);
2197 
2198  GRN_PTR_INIT(&use_columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
2199  GRN_TEXT_INIT(&column_name, 0);
2200  for (i = 0; i < ncolumns; i++) {
2201  if (columns[i]->header.type == GRN_COLUMN_INDEX) {
2202  continue;
2203  }
2204  GRN_BULK_REWIND(&column_name);
2205  grn_column_name_(ctx, columns[i], &column_name);
2206  if (((table->header.type == GRN_TABLE_HASH_KEY ||
2207  table->header.type == GRN_TABLE_PAT_KEY ||
2208  table->header.type == GRN_TABLE_DAT_KEY) &&
2209  GRN_TEXT_LEN(&column_name) == 3 &&
2210  !memcmp(GRN_TEXT_VALUE(&column_name), "_id", 3)) ||
2211  (table->header.type == GRN_TABLE_NO_KEY &&
2212  GRN_TEXT_LEN(&column_name) == 4 &&
2213  !memcmp(GRN_TEXT_VALUE(&column_name), "_key", 4))) {
2214  continue;
2215  }
2216  GRN_PTR_PUT(ctx, &use_columns, columns[i]);
2217  }
2218 
2219  n_use_columns = GRN_BULK_VSIZE(&use_columns) / sizeof(grn_obj *);
2220  GRN_TEXT_PUTC(ctx, outbuf, '[');
2221  for (i = 0; i < n_use_columns; i++) {
2222  grn_obj *column;
2223  column = *((grn_obj **)GRN_BULK_HEAD(&use_columns) + i);
2224  if (i) { GRN_TEXT_PUTC(ctx, outbuf, ','); }
2225  GRN_BULK_REWIND(&column_name);
2226  grn_column_name_(ctx, column, &column_name);
2227  grn_text_otoj(ctx, outbuf, &column_name, NULL);
2228  }
2229  GRN_TEXT_PUTS(ctx, outbuf, "],\n");
2230 
2231  cursor = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1,
2233  for (i = 0; (id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL;
2234  ++i, old_id = id) {
2235  int is_value_column;
2236  int j;
2237  grn_obj buf;
2238  if (i) { GRN_TEXT_PUTS(ctx, outbuf, ",\n"); }
2239  if (table->header.type == GRN_TABLE_NO_KEY && old_id + 1 < id) {
2240  grn_id current_id;
2241  for (current_id = old_id + 1; current_id < id; current_id++) {
2242  GRN_TEXT_PUTS(ctx, outbuf, "[],\n");
2243  GRN_TEXT_PUTS(ctx, &delete_commands, "delete --table ");
2244  dump_obj_name(ctx, &delete_commands, table);
2245  GRN_TEXT_PUTS(ctx, &delete_commands, " --id ");
2246  grn_text_lltoa(ctx, &delete_commands, current_id);
2247  GRN_TEXT_PUTC(ctx, &delete_commands, '\n');
2248  }
2249  }
2250  GRN_TEXT_PUTC(ctx, outbuf, '[');
2251  for (j = 0; j < n_use_columns; j++) {
2252  grn_id range;
2253  grn_obj *column;
2254  column = *((grn_obj **)GRN_BULK_HEAD(&use_columns) + j);
2255  GRN_BULK_REWIND(&column_name);
2256  grn_column_name_(ctx, column, &column_name);
2257  if (GRN_TEXT_LEN(&column_name) == 6 &&
2258  !memcmp(GRN_TEXT_VALUE(&column_name), "_value", 6)) {
2259  is_value_column = 1;
2260  } else {
2261  is_value_column = 0;
2262  }
2263  range = grn_obj_get_range(ctx, column);
2264 
2265  if (j) { GRN_TEXT_PUTC(ctx, outbuf, ','); }
2266  switch (column->header.type) {
2267  case GRN_COLUMN_VAR_SIZE:
2268  case GRN_COLUMN_FIX_SIZE:
2269  switch (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
2270  case GRN_OBJ_COLUMN_VECTOR:
2271  /* TODO: We assume that if |range| is GRN_OBJ_KEY_VAR_SIZE, a vector
2272  is GRN_VECTOR, otherwise GRN_UVECTOR. This is not always
2273  the case, especially by using GRNAPI with C, it's possible
2274  to create GRN_VECTOR with values of constant-size type. */
2275  if (((struct _grn_type *)grn_ctx_at(ctx, range))->obj.header.flags &
2277  GRN_OBJ_INIT(&buf, GRN_VECTOR, 0, range);
2278  grn_obj_get_value(ctx, column, id, &buf);
2279  grn_text_otoj(ctx, outbuf, &buf, NULL);
2280  grn_obj_unlink(ctx, &buf);
2281  } else {
2282  GRN_OBJ_INIT(&buf, GRN_UVECTOR, 0, range);
2283  grn_obj_get_value(ctx, column, id, &buf);
2284  grn_text_otoj(ctx, outbuf, &buf, NULL);
2285  grn_obj_unlink(ctx, &buf);
2286  }
2287  break;
2288  case GRN_OBJ_COLUMN_SCALAR:
2289  {
2290  GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
2291  grn_obj_get_value(ctx, column, id, &buf);
2292  grn_text_otoj(ctx, outbuf, &buf, NULL);
2293  grn_obj_unlink(ctx, &buf);
2294  }
2295  break;
2296  case GRN_OBJ_COLUMN_INDEX:
2297  break;
2298  default:
2300  "unsupported column type: %#x",
2301  column->header.type);
2302  break;
2303  }
2304  break;
2305  case GRN_ACCESSOR:
2306  {
2307  GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
2308  grn_obj_get_value(ctx, column, id, &buf);
2309  /* XXX maybe, grn_obj_get_range() should not unconditionally return
2310  GRN_DB_INT32 when column is GRN_ACCESSOR and
2311  GRN_ACCESSOR_GET_VALUE */
2312  if (is_value_column) {
2313  buf.header.domain = ((grn_db_obj *)table)->range;
2314  }
2315  grn_text_otoj(ctx, outbuf, &buf, NULL);
2316  grn_obj_unlink(ctx, &buf);
2317  }
2318  break;
2319  default:
2321  "unsupported header type %#x",
2322  column->header.type);
2323  break;
2324  }
2325  }
2326  GRN_TEXT_PUTC(ctx, outbuf, ']');
2327  }
2328  GRN_TEXT_PUTS(ctx, outbuf, "\n]\n");
2329  GRN_TEXT_PUT(ctx, outbuf, GRN_TEXT_VALUE(&delete_commands),
2330  GRN_TEXT_LEN(&delete_commands));
2331  grn_obj_unlink(ctx, &delete_commands);
2332  grn_obj_unlink(ctx, &column_name);
2333  grn_obj_unlink(ctx, &use_columns);
2334 
2335  grn_table_cursor_close(ctx, cursor);
2336  for (i = 0; i < ncolumns; i++) {
2337  grn_obj_unlink(ctx, columns[i]);
2338  }
2339  grn_obj_unlink(ctx, &columnbuf);
2340 }
2341 
2342 static void
2343 dump_table(grn_ctx *ctx, grn_obj *outbuf, grn_obj *table,
2344  grn_obj *pending_columns)
2345 {
2346  grn_obj *domain = NULL, *range = NULL;
2347  grn_obj_flags default_flags = GRN_OBJ_PERSISTENT;
2348  grn_obj *default_tokenizer;
2349  grn_obj *normalizer;
2350  grn_obj buf;
2351 
2352  switch (table->header.type) {
2353  case GRN_TABLE_HASH_KEY:
2354  case GRN_TABLE_PAT_KEY:
2355  case GRN_TABLE_DAT_KEY:
2356  domain = grn_ctx_at(ctx, table->header.domain);
2357  break;
2358  default:
2359  break;
2360  }
2361 
2362  GRN_TEXT_PUTS(ctx, outbuf, "table_create ");
2363  dump_obj_name(ctx, outbuf, table);
2364  GRN_TEXT_PUTC(ctx, outbuf, ' ');
2365  GRN_TEXT_INIT(&buf, 0);
2366  grn_table_create_flags_to_text(ctx, &buf, table->header.flags & ~default_flags);
2367  GRN_TEXT_PUT(ctx, outbuf, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2368  GRN_OBJ_FIN(ctx, &buf);
2369  if (domain) {
2370  GRN_TEXT_PUTC(ctx, outbuf, ' ');
2371  dump_obj_name(ctx, outbuf, domain);
2372  }
2373  if (((grn_db_obj *)table)->range != GRN_ID_NIL) {
2374  range = grn_ctx_at(ctx, ((grn_db_obj *)table)->range);
2375  if (!range) {
2376  // ERR(GRN_RANGE_ERROR, "couldn't get table's value_type object");
2377  return;
2378  }
2379  if (table->header.type != GRN_TABLE_NO_KEY) {
2380  GRN_TEXT_PUTC(ctx, outbuf, ' ');
2381  } else {
2382  GRN_TEXT_PUTS(ctx, outbuf, " --value_type ");
2383  }
2384  dump_obj_name(ctx, outbuf, range);
2385  grn_obj_unlink(ctx, range);
2386  }
2387  default_tokenizer = grn_obj_get_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER,
2388  NULL);
2389  if (default_tokenizer) {
2390  GRN_TEXT_PUTS(ctx, outbuf, " --default_tokenizer ");
2391  dump_obj_name(ctx, outbuf, default_tokenizer);
2392  }
2393  normalizer = grn_obj_get_info(ctx, table, GRN_INFO_NORMALIZER, NULL);
2394  if (normalizer) {
2395  GRN_TEXT_PUTS(ctx, outbuf, " --normalizer ");
2396  dump_obj_name(ctx, outbuf, normalizer);
2397  }
2398 
2399  GRN_TEXT_PUTC(ctx, outbuf, '\n');
2400 
2401  if (domain) {
2402  grn_obj_unlink(ctx, domain);
2403  }
2404 
2405  dump_columns(ctx, outbuf, table, pending_columns);
2406 }
2407 
2408 /* can we move this to groonga.h? */
2409 #define GRN_PTR_POP(obj,value) do {\
2410  if (GRN_BULK_VSIZE(obj) >= sizeof(grn_obj *)) {\
2411  GRN_BULK_INCR_LEN((obj), -(sizeof(grn_obj *)));\
2412  value = *(grn_obj **)(GRN_BULK_CURR(obj));\
2413  } else {\
2414  value = NULL;\
2415  }\
2416 } while (0)
2417 
2418 static void
2419 dump_schema(grn_ctx *ctx, grn_obj *outbuf)
2420 {
2421  grn_obj *db = ctx->impl->db;
2422  grn_table_cursor *cur;
2423  if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
2424  GRN_CURSOR_BY_ID))) {
2425  grn_id id;
2426  grn_obj pending_columns;
2427 
2428  GRN_PTR_INIT(&pending_columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
2429  while ((id = grn_table_cursor_next(ctx, cur)) != GRN_ID_NIL) {
2430  grn_obj *object;
2431 
2432  if ((object = grn_ctx_at(ctx, id))) {
2433  switch (object->header.type) {
2434  case GRN_TABLE_HASH_KEY:
2435  case GRN_TABLE_PAT_KEY:
2436  case GRN_TABLE_DAT_KEY:
2437  case GRN_TABLE_NO_KEY:
2438  dump_table(ctx, outbuf, object, &pending_columns);
2439  break;
2440  default:
2441  break;
2442  }
2443  grn_obj_unlink(ctx, object);
2444  } else {
2445  /* XXX: this clause is executed when MeCab tokenizer is enabled in
2446  database but the groonga isn't supported MeCab.
2447  We should return error mesage about it and error exit status
2448  but it's too difficult for this architecture. :< */
2449  ERRCLR(ctx);
2450  }
2451  }
2452  grn_table_cursor_close(ctx, cur);
2453 
2454  while (GRN_TRUE) {
2455  grn_obj *table, *column;
2456  GRN_PTR_POP(&pending_columns, column);
2457  if (!column) {
2458  break;
2459  }
2460  table = grn_ctx_at(ctx, column->header.domain);
2461  dump_column(ctx, outbuf, table, column);
2462  grn_obj_unlink(ctx, column);
2463  grn_obj_unlink(ctx, table);
2464  }
2465  grn_obj_close(ctx, &pending_columns);
2466  }
2467 }
2468 
2469 static void
2470 dump_selected_tables_records(grn_ctx *ctx, grn_obj *outbuf, grn_obj *tables)
2471 {
2472  const char *p, *e;
2473 
2474  p = GRN_TEXT_VALUE(tables);
2475  e = p + GRN_TEXT_LEN(tables);
2476  while (p < e) {
2477  int len;
2478  grn_obj *table;
2479  const char *token, *token_e;
2480 
2481  if ((len = grn_isspace(p, ctx->encoding))) {
2482  p += len;
2483  continue;
2484  }
2485 
2486  token = p;
2487  if (!(('a' <= *p && *p <= 'z') ||
2488  ('A' <= *p && *p <= 'Z') ||
2489  (*p == '_'))) {
2490  while (p < e && !grn_isspace(p, ctx->encoding)) {
2491  p++;
2492  }
2493  GRN_LOG(ctx, GRN_LOG_WARNING, "invalid table name is ignored: <%.*s>\n",
2494  (int)(p - token), token);
2495  continue;
2496  }
2497  while (p < e &&
2498  (('a' <= *p && *p <= 'z') ||
2499  ('A' <= *p && *p <= 'Z') ||
2500  ('0' <= *p && *p <= '9') ||
2501  (*p == '_'))) {
2502  p++;
2503  }
2504  token_e = p;
2505  while (p < e && (len = grn_isspace(p, ctx->encoding))) {
2506  p += len;
2507  continue;
2508  }
2509  if (p < e && *p == ',') {
2510  p++;
2511  }
2512 
2513  if ((table = grn_ctx_get(ctx, token, token_e - token))) {
2514  dump_records(ctx, outbuf, table);
2515  grn_obj_unlink(ctx, table);
2516  } else {
2517  GRN_LOG(ctx, GRN_LOG_WARNING,
2518  "nonexistent table name is ignored: <%.*s>\n",
2519  (int)(token_e - token), token);
2520  }
2521  }
2522 }
2523 
2524 static void
2525 dump_all_records(grn_ctx *ctx, grn_obj *outbuf)
2526 {
2527  grn_obj *db = ctx->impl->db;
2528  grn_table_cursor *cur;
2529  if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
2530  GRN_CURSOR_BY_ID))) {
2531  grn_id id;
2532 
2533  while ((id = grn_table_cursor_next(ctx, cur)) != GRN_ID_NIL) {
2534  grn_obj *table;
2535 
2536  if ((table = grn_ctx_at(ctx, id))) {
2537  dump_records(ctx, outbuf, table);
2538  grn_obj_unlink(ctx, table);
2539  } else {
2540  /* XXX: this clause is executed when MeCab tokenizer is enabled in
2541  database but the groonga isn't supported MeCab.
2542  We should return error mesage about it and error exit status
2543  but it's too difficult for this architecture. :< */
2544  ERRCLR(ctx);
2545  }
2546  }
2547  grn_table_cursor_close(ctx, cur);
2548  }
2549 }
2550 
2551 static grn_obj *
2552 proc_dump(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2553 {
2554  grn_obj *outbuf = ctx->impl->outbuf;
2556  ctx->impl->mime_type = "text/x-groonga-command-list";
2557  dump_schema(ctx, outbuf);
2558  /* To update index columns correctly, we first create the whole schema, then
2559  load non-derivative records, while skipping records of index columns. That
2560  way, groonga will silently do the job of updating index columns for us. */
2561  if (GRN_TEXT_LEN(VAR(0)) > 0) {
2562  dump_selected_tables_records(ctx, outbuf, VAR(0));
2563  } else {
2564  dump_all_records(ctx, outbuf);
2565  }
2566 
2567  /* remove the last newline because another one will be added by the calller.
2568  maybe, the caller of proc functions currently doesn't consider the
2569  possibility of multiple-line output from proc functions. */
2570  if (GRN_BULK_VSIZE(outbuf) > 0) {
2571  grn_bulk_truncate(ctx, outbuf, GRN_BULK_VSIZE(outbuf) - 1);
2572  }
2573  return NULL;
2574 }
2575 
2576 static grn_obj *
2577 proc_cache_limit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2578 {
2579  grn_cache *cache;
2580  unsigned int current_max_n_entries;
2581 
2582  cache = grn_cache_current_get(ctx);
2583  current_max_n_entries = grn_cache_get_max_n_entries(ctx, cache);
2584  if (GRN_TEXT_LEN(VAR(0))) {
2585  const char *rest;
2586  uint32_t max = grn_atoui(GRN_TEXT_VALUE(VAR(0)),
2587  GRN_BULK_CURR(VAR(0)), &rest);
2588  if (GRN_BULK_CURR(VAR(0)) == rest) {
2589  grn_cache_set_max_n_entries(ctx, cache, max);
2590  } else {
2592  "max value is invalid unsigned integer format: <%.*s>",
2593  (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
2594  }
2595  }
2596  if (ctx->rc == GRN_SUCCESS) {
2597  GRN_OUTPUT_INT64(current_max_n_entries);
2598  }
2599  return NULL;
2600 }
2601 
2602 static grn_obj *
2603 proc_register(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2604 {
2605  if (GRN_TEXT_LEN(VAR(0))) {
2606  const char *name;
2607  GRN_TEXT_PUTC(ctx, VAR(0), '\0');
2608  name = GRN_TEXT_VALUE(VAR(0));
2609  grn_plugin_register(ctx, name);
2610  } else {
2611  ERR(GRN_INVALID_ARGUMENT, "path is required");
2612  }
2613  GRN_OUTPUT_BOOL(!ctx->rc);
2614  return NULL;
2615 }
2616 
2617 void grn_ii_buffer_check(grn_ctx *ctx, grn_ii *ii, uint32_t seg);
2618 
2619 static grn_obj *
2620 proc_check(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2621 {
2622  grn_obj *obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)));
2623  if (!obj) {
2625  "no such object: <%.*s>", (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
2626  GRN_OUTPUT_BOOL(!ctx->rc);
2627  } else {
2628  switch (obj->header.type) {
2629  case GRN_DB :
2630  GRN_OUTPUT_BOOL(!ctx->rc);
2631  break;
2632  case GRN_TABLE_PAT_KEY :
2633  grn_pat_check(ctx, (grn_pat *)obj);
2634  break;
2635  case GRN_TABLE_HASH_KEY :
2636  grn_hash_check(ctx, (grn_hash *)obj);
2637  break;
2638  case GRN_TABLE_DAT_KEY :
2639  case GRN_TABLE_NO_KEY :
2640  case GRN_COLUMN_FIX_SIZE :
2641  GRN_OUTPUT_BOOL(!ctx->rc);
2642  break;
2643  case GRN_COLUMN_VAR_SIZE :
2644  grn_ja_check(ctx, (grn_ja *)obj);
2645  break;
2646  case GRN_COLUMN_INDEX :
2647  {
2648  grn_ii *ii = (grn_ii *)obj;
2649  struct grn_ii_header *h = ii->header;
2650  char buf[8];
2651  GRN_OUTPUT_ARRAY_OPEN("RESULT", 8);
2652  {
2653  uint32_t i, j, g =0, a = 0, b = 0;
2654  uint32_t max = 0;
2655  for (i = h->bgqtail; i != h->bgqhead; i = ((i + 1) & (GRN_II_BGQSIZE - 1))) {
2656  j = h->bgqbody[i];
2657  g++;
2658  if (j > max) { max = j; }
2659  }
2660  for (i = 0; i < GRN_II_MAX_LSEG; i++) {
2661  j = h->binfo[i];
2662  if (j < 0x20000) {
2663  if (j > max) { max = j; }
2664  b++;
2665  }
2666  }
2667  for (i = 0; i < GRN_II_MAX_LSEG; i++) {
2668  j = h->ainfo[i];
2669  if (j < 0x20000) {
2670  if (j > max) { max = j; }
2671  a++;
2672  }
2673  }
2674  GRN_OUTPUT_MAP_OPEN("SUMMARY", 8);
2675  GRN_OUTPUT_CSTR("flags");
2676  grn_itoh(h->flags, buf, 8);
2677  GRN_OUTPUT_STR(buf, 8);
2678  GRN_OUTPUT_CSTR("max sid");
2679  GRN_OUTPUT_INT64(h->smax);
2680  GRN_OUTPUT_CSTR("number of garbage segments");
2681  GRN_OUTPUT_INT64(g);
2682  GRN_OUTPUT_CSTR("number of array segments");
2683  GRN_OUTPUT_INT64(a);
2684  GRN_OUTPUT_CSTR("max id of array segment");
2685  GRN_OUTPUT_INT64(h->amax);
2686  GRN_OUTPUT_CSTR("number of buffer segments");
2688  GRN_OUTPUT_CSTR("max id of buffer segment");
2689  GRN_OUTPUT_INT64(h->bmax);
2690  GRN_OUTPUT_CSTR("max id of physical segment in use");
2691  GRN_OUTPUT_INT64(max);
2692  GRN_OUTPUT_CSTR("number of unmanaged segments");
2693  GRN_OUTPUT_INT64(h->pnext - a - b - g);
2694  GRN_OUTPUT_CSTR("total chunk size");
2696  for (max = 0, i = 0; i < (GRN_II_MAX_CHUNK >> 3); i++) {
2697  if ((j = h->chunks[i])) {
2698  int k;
2699  for (k = 0; k < 8; k++) {
2700  if ((j & (1 << k))) { max = (i << 3) + j; }
2701  }
2702  }
2703  }
2704  GRN_OUTPUT_CSTR("max id of chunk segments in use");
2705  GRN_OUTPUT_INT64(max);
2706  GRN_OUTPUT_CSTR("number of garbage chunk");
2708  for (i = 0; i <= GRN_II_N_CHUNK_VARIATION; i++) {
2709  GRN_OUTPUT_INT64(h->ngarbages[i]);
2710  }
2713  for (i = 0; i < GRN_II_MAX_LSEG; i++) {
2714  if (h->binfo[i] < 0x20000) { grn_ii_buffer_check(ctx, ii, i); }
2715  }
2716  }
2718  }
2719  break;
2720  }
2721  }
2722  return NULL;
2723 }
2724 
2725 static grn_obj *
2726 proc_truncate(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2727 {
2728  int table_name_len = GRN_TEXT_LEN(VAR(0));
2729  if (table_name_len == 0) {
2730  ERR(GRN_INVALID_ARGUMENT, "table name is missing");
2731  } else {
2732  const char *table_name = GRN_TEXT_VALUE(VAR(0));
2733  grn_obj *table = grn_ctx_get(ctx, table_name, table_name_len);
2734  if (!table) {
2736  "no such table: <%.*s>", table_name_len, table_name);
2737  } else {
2738  switch (table->header.type) {
2739  case GRN_TABLE_HASH_KEY :
2740  case GRN_TABLE_PAT_KEY :
2741  case GRN_TABLE_DAT_KEY :
2742  case GRN_TABLE_NO_KEY :
2743  grn_table_truncate(ctx, table);
2744  break;
2745  default:
2746  {
2747  grn_obj buffer;
2748  GRN_TEXT_INIT(&buffer, 0);
2749  grn_inspect(ctx, &buffer, table);
2751  "not a table object: %.*s",
2752  (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
2753  GRN_OBJ_FIN(ctx, &buffer);
2754  }
2755  break;
2756  }
2757  }
2758  }
2759  GRN_OUTPUT_BOOL(!ctx->rc);
2760  return NULL;
2761 }
2762 
2763 static int
2764 parse_normalize_flags(grn_ctx *ctx, grn_obj *flag_names)
2765 {
2766  int flags = 0;
2767  const char *names, *names_end;
2768  int length;
2769 
2770  names = GRN_TEXT_VALUE(flag_names);
2771  length = GRN_TEXT_LEN(flag_names);
2772  names_end = names + length;
2773  while (names < names_end) {
2774  if (*names == '|' || *names == ' ') {
2775  names += 1;
2776  continue;
2777  }
2778 
2779 #define CHECK_FLAG(name)\
2780  if (((names_end - names) >= (sizeof(#name) - 1)) &&\
2781  (!memcmp(names, #name, sizeof(#name) - 1))) {\
2782  flags |= GRN_STRING_ ## name;\
2783  names += sizeof(#name);\
2784  continue;\
2785  }
2786 
2787  CHECK_FLAG(REMOVE_BLANK);
2788  CHECK_FLAG(WITH_TYPES);
2789  CHECK_FLAG(WITH_CHECKS);
2790  CHECK_FLAG(REMOVE_TOKENIZED_DELIMITER);
2791 
2792 #define GRN_STRING_NONE 0
2793  CHECK_FLAG(NONE);
2794 #undef GRN_STRING_NONE
2795 
2796  ERR(GRN_INVALID_ARGUMENT, "[normalize] invalid flag: <%.*s>",
2797  (int)(names_end - names), names);
2798  return 0;
2799 #undef CHECK_FLAG
2800  }
2801 
2802  return flags;
2803 }
2804 
2805 static const char *
2806 char_type_name(grn_char_type type)
2807 {
2808  const char *name = "unknown";
2809 
2810  switch (type) {
2811  case GRN_CHAR_NULL :
2812  name = "null";
2813  break;
2814  case GRN_CHAR_ALPHA :
2815  name = "alpha";
2816  break;
2817  case GRN_CHAR_DIGIT :
2818  name = "digit";
2819  break;
2820  case GRN_CHAR_SYMBOL :
2821  name = "symbol";
2822  break;
2823  case GRN_CHAR_HIRAGANA :
2824  name = "hiragana";
2825  break;
2826  case GRN_CHAR_KATAKANA :
2827  name = "katakana";
2828  break;
2829  case GRN_CHAR_KANJI :
2830  name = "kanji";
2831  break;
2832  case GRN_CHAR_OTHERS :
2833  name = "others";
2834  break;
2835  }
2836 
2837  return name;
2838 }
2839 
2840 static grn_obj *
2841 proc_normalize(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
2842 {
2843  grn_obj *normalizer_name;
2844  grn_obj *string;
2845  grn_obj *flag_names;
2846 
2847  normalizer_name = VAR(0);
2848  string = VAR(1);
2849  flag_names = VAR(2);
2850  if (GRN_TEXT_LEN(normalizer_name) == 0) {
2851  ERR(GRN_INVALID_ARGUMENT, "normalizer name is missing");
2852  GRN_OUTPUT_CSTR("");
2853  return NULL;
2854  }
2855 
2856  {
2857  grn_obj *normalizer;
2859  int flags;
2860  unsigned int normalized_n_characters;
2861 
2862  flags = parse_normalize_flags(ctx, flag_names);
2863  normalizer = grn_ctx_get(ctx,
2864  GRN_TEXT_VALUE(normalizer_name),
2865  GRN_TEXT_LEN(normalizer_name));
2866  if (!normalizer) {
2868  "unknown normalizer: <%.*s>",
2869  (int)GRN_TEXT_LEN(normalizer_name),
2870  GRN_TEXT_VALUE(normalizer_name));
2871  GRN_OUTPUT_CSTR("");
2872  return NULL;
2873  }
2874 
2875  grn_string = grn_string_open(ctx,
2876  GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
2877  normalizer, flags);
2878  grn_obj_unlink(ctx, normalizer);
2879 
2880  GRN_OUTPUT_MAP_OPEN("RESULT", 2);
2881  {
2882  const char *normalized;
2883  unsigned int normalized_length_in_bytes;
2884 
2885  grn_string_get_normalized(ctx, grn_string,
2886  &normalized,
2887  &normalized_length_in_bytes,
2888  &normalized_n_characters);
2889  GRN_OUTPUT_CSTR("normalized");
2890  GRN_OUTPUT_STR(normalized, normalized_length_in_bytes);
2891  }
2892  {
2893  const unsigned char *types;
2894 
2895  types = grn_string_get_types(ctx, grn_string);
2896  GRN_OUTPUT_CSTR("types");
2897  if (types) {
2898  unsigned int i;
2899  GRN_OUTPUT_ARRAY_OPEN("types", normalized_n_characters);
2900  for (i = 0; i < normalized_n_characters; i++) {
2901  GRN_OUTPUT_CSTR(char_type_name(types[i]));
2902  }
2904  } else {
2905  GRN_OUTPUT_ARRAY_OPEN("types", 0);
2907  }
2908  }
2910 
2911  grn_obj_unlink(ctx, grn_string);
2912  }
2913 
2914  return NULL;
2915 }
2916 
2917 static unsigned int
2918 parse_tokenize_flags(grn_ctx *ctx, grn_obj *flag_names)
2919 {
2920  unsigned int flags = 0;
2921  const char *names, *names_end;
2922  int length;
2923 
2924  names = GRN_TEXT_VALUE(flag_names);
2925  length = GRN_TEXT_LEN(flag_names);
2926  names_end = names + length;
2927  while (names < names_end) {
2928  if (*names == '|' || *names == ' ') {
2929  names += 1;
2930  continue;
2931  }
2932 
2933 #define CHECK_FLAG(name)\
2934  if (((names_end - names) >= (sizeof(#name) - 1)) &&\
2935  (!memcmp(names, #name, sizeof(#name) - 1))) {\
2936  flags |= GRN_TOKEN_ ## name;\
2937  names += sizeof(#name);\
2938  continue;\
2939  }
2940 
2941  CHECK_FLAG(ENABLE_TOKENIZED_DELIMITER);
2942 
2943 #define GRN_TOKEN_NONE 0
2944  CHECK_FLAG(NONE);
2945 #undef GRN_TOKEN_NONE
2946 
2947  ERR(GRN_INVALID_ARGUMENT, "[tokenize] invalid flag: <%.*s>",
2948  (int)(names_end - names), names);
2949  return 0;
2950 #undef CHECK_FLAG
2951  }
2952 
2953  return flags;
2954 }
2955 
2956 typedef struct {
2958  int32_t position;
2959 } tokenize_token;
2960 
2961 static void
2962 output_tokens(grn_ctx *ctx, grn_obj *tokens, grn_hash *lexicon)
2963 {
2964  int i, n_tokens = 0;
2965 
2966  if (tokens) {
2967  n_tokens = GRN_BULK_VSIZE(tokens) / sizeof(tokenize_token);
2968  }
2969 
2970  GRN_OUTPUT_ARRAY_OPEN("tokens", n_tokens);
2971  for (i = 0; i < n_tokens; i++) {
2972  tokenize_token *token;
2973  char value[GRN_TABLE_MAX_KEY_SIZE];
2974  unsigned int value_size;
2975 
2976  token = ((tokenize_token *)(GRN_BULK_HEAD(tokens))) + i;
2977 
2978  GRN_OUTPUT_MAP_OPEN("token", 2);
2979 
2980  GRN_OUTPUT_CSTR("value");
2981  value_size = grn_hash_get_key(ctx, lexicon, token->id,
2982  value, GRN_TABLE_MAX_KEY_SIZE);
2983  GRN_OUTPUT_STR(value, value_size);
2984 
2985  GRN_OUTPUT_CSTR("position");
2986  GRN_OUTPUT_INT32(token->position);
2987 
2989  }
2991 }
2992 
2993 static grn_hash *
2994 create_lexicon_for_tokenize(grn_ctx *ctx,
2995  grn_obj *tokenizer_name,
2996  grn_obj *normalizer_name)
2997 {
2998  grn_hash *lexicon;
2999  grn_obj *tokenizer;
3000  grn_obj *normalizer = NULL;
3001 
3002  tokenizer = grn_ctx_get(ctx,
3003  GRN_TEXT_VALUE(tokenizer_name),
3004  GRN_TEXT_LEN(tokenizer_name));
3005  if (!tokenizer) {
3007  "[tokenize] unknown tokenizer: <%.*s>",
3008  (int)GRN_TEXT_LEN(tokenizer_name),
3009  GRN_TEXT_VALUE(tokenizer_name));
3010  return NULL;
3011  }
3012 
3013  if (GRN_TEXT_LEN(normalizer_name) > 0) {
3014  normalizer = grn_ctx_get(ctx,
3015  GRN_TEXT_VALUE(normalizer_name),
3016  GRN_TEXT_LEN(normalizer_name));
3017  if (!normalizer) {
3018  grn_obj_unlink(ctx, tokenizer);
3020  "[tokenize] unknown normalizer: <%.*s>",
3021  (int)GRN_TEXT_LEN(normalizer_name),
3022  GRN_TEXT_VALUE(normalizer_name));
3023  return NULL;
3024  }
3025  }
3026 
3027  lexicon = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, 0,
3029  grn_obj_set_info(ctx, (grn_obj *)lexicon,
3030  GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
3031  grn_obj_unlink(ctx, tokenizer);
3032  if (normalizer) {
3033  grn_obj_set_info(ctx, (grn_obj *)lexicon,
3034  GRN_INFO_NORMALIZER, normalizer);
3035  grn_obj_unlink(ctx, normalizer);
3036  }
3037 
3038  return lexicon;
3039 }
3040 
3041 static void
3042 tokenize(grn_ctx *ctx, grn_hash *lexicon, grn_obj *string, unsigned int flags,
3043  grn_obj *tokens)
3044 {
3045  grn_token *token;
3046 
3047  token = grn_token_open(ctx, (grn_obj *)lexicon,
3048  GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
3049  GRN_TOKEN_ADD, flags);
3050  if (!token) {
3051  return;
3052  }
3053 
3054  while (token->status == GRN_TOKEN_DOING) {
3055  grn_id token_id = grn_token_next(ctx, token);
3056  tokenize_token *current_token;
3057  if (token_id == GRN_ID_NIL) {
3058  continue;
3059  }
3060  grn_bulk_space(ctx, tokens, sizeof(tokenize_token));
3061  current_token = ((tokenize_token *)(GRN_BULK_CURR(tokens))) - 1;
3062  current_token->id = token_id;
3063  current_token->position = token->pos;
3064  }
3065  grn_token_close(ctx, token);
3066 }
3067 
3068 static grn_obj *
3069 proc_tokenize(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3070 {
3071  grn_obj *tokenizer_name;
3072  grn_obj *string;
3073  grn_obj *normalizer_name;
3074  grn_obj *flag_names;
3075 
3076  tokenizer_name = VAR(0);
3077  string = VAR(1);
3078  normalizer_name = VAR(2);
3079  flag_names = VAR(3);
3080 
3081  if (GRN_TEXT_LEN(tokenizer_name) == 0) {
3082  ERR(GRN_INVALID_ARGUMENT, "[tokenize] tokenizer name is missing");
3083  output_tokens(ctx, NULL, NULL);
3084  return NULL;
3085  }
3086 
3087  if (GRN_TEXT_LEN(string) == 0) {
3088  ERR(GRN_INVALID_ARGUMENT, "[tokenize] string is missing");
3089  output_tokens(ctx, NULL, NULL);
3090  return NULL;
3091  }
3092 
3093  {
3094  unsigned int flags;
3095  grn_hash *lexicon;
3096  grn_obj tokens;
3097 
3098  flags = parse_tokenize_flags(ctx, flag_names);
3099  if (ctx->rc != GRN_SUCCESS) {
3100  output_tokens(ctx, NULL, NULL);
3101  return NULL;
3102  }
3103 
3104  lexicon = create_lexicon_for_tokenize(ctx, tokenizer_name, normalizer_name);
3105  if (!lexicon) {
3106  output_tokens(ctx, NULL, NULL);
3107  return NULL;
3108  }
3109 
3111  tokenize(ctx, lexicon, string, flags, &tokens);
3112  output_tokens(ctx, &tokens, lexicon);
3113  GRN_OBJ_FIN(ctx, &tokens);
3114 
3115  grn_hash_close(ctx, lexicon);
3116  }
3117 
3118  return NULL;
3119 }
3120 
3121 static grn_obj *
3122 func_rand(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3123 {
3124  int val;
3125  grn_obj *obj;
3126  if (nargs > 0) {
3127  int max = GRN_INT32_VALUE(args[0]);
3128  val = (int) (1.0 * max * rand() / (RAND_MAX + 1.0));
3129  } else {
3130  val = rand();
3131  }
3132  if ((obj = GRN_PROC_ALLOC(GRN_DB_INT32, 0))) {
3133  GRN_INT32_SET(ctx, obj, val);
3134  }
3135  return obj;
3136 }
3137 
3138 static grn_obj *
3139 func_now(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3140 {
3141  grn_obj *obj;
3142  if ((obj = GRN_PROC_ALLOC(GRN_DB_TIME, 0))) {
3143  GRN_TIME_NOW(ctx, obj);
3144  }
3145  return obj;
3146 }
3147 
3148 static inline grn_bool
3149 is_comparable_number_type(grn_id type)
3150 {
3151  return GRN_DB_INT8 <= type && type <= GRN_DB_TIME;
3152 }
3153 
3154 static inline grn_id
3155 larger_number_type(grn_id type1, grn_id type2)
3156 {
3157  if (type1 == type2) {
3158  return type1;
3159  }
3160 
3161  switch (type1) {
3162  case GRN_DB_FLOAT :
3163  return type1;
3164  case GRN_DB_TIME :
3165  if (type2 == GRN_DB_FLOAT) {
3166  return type2;
3167  } else {
3168  return type1;
3169  }
3170  default :
3171  if (type2 > type1) {
3172  return type2;
3173  } else {
3174  return type1;
3175  }
3176  }
3177 }
3178 
3179 static inline grn_id
3180 smaller_number_type(grn_id type1, grn_id type2)
3181 {
3182  if (type1 == type2) {
3183  return type1;
3184  }
3185 
3186  switch (type1) {
3187  case GRN_DB_FLOAT :
3188  return type1;
3189  case GRN_DB_TIME :
3190  if (type2 == GRN_DB_FLOAT) {
3191  return type2;
3192  } else {
3193  return type1;
3194  }
3195  default :
3196  {
3197  grn_id smaller_number_type;
3198  if (type2 > type1) {
3199  smaller_number_type = type2;
3200  } else {
3201  smaller_number_type = type1;
3202  }
3203  switch (smaller_number_type) {
3204  case GRN_DB_UINT8 :
3205  return GRN_DB_INT8;
3206  case GRN_DB_UINT16 :
3207  return GRN_DB_INT16;
3208  case GRN_DB_UINT32 :
3209  return GRN_DB_INT32;
3210  case GRN_DB_UINT64 :
3211  return GRN_DB_INT64;
3212  default :
3213  return smaller_number_type;
3214  }
3215  }
3216  }
3217 }
3218 
3219 static inline grn_bool
3220 is_negative_value(grn_obj *number)
3221 {
3222  switch (number->header.domain) {
3223  case GRN_DB_INT8 :
3224  return GRN_INT8_VALUE(number) < 0;
3225  case GRN_DB_INT16 :
3226  return GRN_INT16_VALUE(number) < 0;
3227  case GRN_DB_INT32 :
3228  return GRN_INT32_VALUE(number) < 0;
3229  case GRN_DB_INT64 :
3230  return GRN_INT64_VALUE(number) < 0;
3231  case GRN_DB_TIME :
3232  return GRN_TIME_VALUE(number) < 0;
3233  case GRN_DB_FLOAT :
3234  return GRN_FLOAT_VALUE(number) < 0;
3235  default :
3236  return GRN_FALSE;
3237  }
3238 }
3239 
3240 static inline grn_bool
3241 number_safe_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, grn_id type)
3242 {
3243  grn_obj_reinit(ctx, dest, type, 0);
3244  if (src->header.domain == type) {
3245  GRN_TEXT_SET(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
3246  return GRN_TRUE;
3247  }
3248 
3249  switch (type) {
3250  case GRN_DB_UINT8 :
3251  if (is_negative_value(src)) {
3252  GRN_UINT8_SET(ctx, dest, 0);
3253  return GRN_TRUE;
3254  }
3255  case GRN_DB_UINT16 :
3256  if (is_negative_value(src)) {
3257  GRN_UINT16_SET(ctx, dest, 0);
3258  return GRN_TRUE;
3259  }
3260  case GRN_DB_UINT32 :
3261  if (is_negative_value(src)) {
3262  GRN_UINT32_SET(ctx, dest, 0);
3263  return GRN_TRUE;
3264  }
3265  case GRN_DB_UINT64 :
3266  if (is_negative_value(src)) {
3267  GRN_UINT64_SET(ctx, dest, 0);
3268  return GRN_TRUE;
3269  }
3270  default :
3271  return grn_obj_cast(ctx, src, dest, GRN_FALSE) == GRN_SUCCESS;
3272  }
3273 }
3274 
3275 static inline int
3276 compare_number(grn_ctx *ctx, grn_obj *number1, grn_obj *number2, grn_id type)
3277 {
3278 #define COMPARE_AND_RETURN(type, value1, value2)\
3279  {\
3280  type computed_value1 = value1;\
3281  type computed_value2 = value2;\
3282  if (computed_value1 > computed_value2) {\
3283  return 1;\
3284  } else if (computed_value1 < computed_value2) {\
3285  return -1;\
3286  } else {\
3287  return 0;\
3288  }\
3289  }
3290 
3291  switch (type) {
3292  case GRN_DB_INT8 :
3293  COMPARE_AND_RETURN(int8_t,
3294  GRN_INT8_VALUE(number1),
3295  GRN_INT8_VALUE(number2));
3296  case GRN_DB_UINT8 :
3297  COMPARE_AND_RETURN(uint8_t,
3298  GRN_UINT8_VALUE(number1),
3299  GRN_UINT8_VALUE(number2));
3300  case GRN_DB_INT16 :
3301  COMPARE_AND_RETURN(int16_t,
3302  GRN_INT16_VALUE(number1),
3303  GRN_INT16_VALUE(number2));
3304  case GRN_DB_UINT16 :
3305  COMPARE_AND_RETURN(uint16_t,
3306  GRN_UINT16_VALUE(number1),
3307  GRN_UINT16_VALUE(number2));
3308  case GRN_DB_INT32 :
3309  COMPARE_AND_RETURN(int32_t,
3310  GRN_INT32_VALUE(number1),
3311  GRN_INT32_VALUE(number2));
3312  case GRN_DB_UINT32 :
3313  COMPARE_AND_RETURN(uint32_t,
3314  GRN_UINT32_VALUE(number1),
3315  GRN_UINT32_VALUE(number2));
3316  case GRN_DB_INT64 :
3317  COMPARE_AND_RETURN(int64_t,
3318  GRN_INT64_VALUE(number1),
3319  GRN_INT64_VALUE(number2));
3320  case GRN_DB_UINT64 :
3321  COMPARE_AND_RETURN(uint64_t,
3322  GRN_UINT64_VALUE(number1),
3323  GRN_UINT64_VALUE(number2));
3324  case GRN_DB_FLOAT :
3325  COMPARE_AND_RETURN(double,
3326  GRN_FLOAT_VALUE(number1),
3327  GRN_FLOAT_VALUE(number2));
3328  case GRN_DB_TIME :
3329  COMPARE_AND_RETURN(int64_t,
3330  GRN_TIME_VALUE(number1),
3331  GRN_TIME_VALUE(number2));
3332  default :
3333  return 0;
3334  }
3335 
3336 #undef COMPARE_AND_RETURN
3337 }
3338 
3339 static grn_obj *
3340 func_max(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3341 {
3342  grn_obj *max;
3343  grn_id cast_type = GRN_DB_INT8;
3344  grn_obj casted_max, casted_number;
3345  int i;
3346 
3347  max = GRN_PROC_ALLOC(GRN_DB_VOID, 0);
3348  if (!max) {
3349  return max;
3350  }
3351 
3352  GRN_VOID_INIT(&casted_max);
3353  GRN_VOID_INIT(&casted_number);
3354  for (i = 0; i < nargs; i++) {
3355  grn_obj *number = args[i];
3356  grn_id domain = number->header.domain;
3357  if (!is_comparable_number_type(domain)) {
3358  continue;
3359  }
3360  cast_type = larger_number_type(cast_type, domain);
3361  if (!number_safe_cast(ctx, number, &casted_number, cast_type)) {
3362  continue;
3363  }
3364  if (max->header.domain == GRN_DB_VOID) {
3365  grn_obj_reinit(ctx, max, cast_type, 0);
3366  GRN_TEXT_SET(ctx, max,
3367  GRN_TEXT_VALUE(&casted_number),
3368  GRN_TEXT_LEN(&casted_number));
3369  continue;
3370  }
3371 
3372  if (max->header.domain != cast_type) {
3373  if (!number_safe_cast(ctx, max, &casted_max, cast_type)) {
3374  continue;
3375  }
3376  grn_obj_reinit(ctx, max, cast_type, 0);
3377  GRN_TEXT_SET(ctx, max,
3378  GRN_TEXT_VALUE(&casted_max),
3379  GRN_TEXT_LEN(&casted_max));
3380  }
3381  if (compare_number(ctx, &casted_number, max, cast_type) > 0) {
3382  grn_obj_reinit(ctx, max, cast_type, 0);
3383  GRN_TEXT_SET(ctx, max,
3384  GRN_TEXT_VALUE(&casted_number),
3385  GRN_TEXT_LEN(&casted_number));
3386  }
3387  }
3388  GRN_OBJ_FIN(ctx, &casted_max);
3389  GRN_OBJ_FIN(ctx, &casted_number);
3390 
3391  return max;
3392 }
3393 
3394 static grn_obj *
3395 func_min(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3396 {
3397  grn_obj *min;
3398  grn_id cast_type = GRN_DB_INT8;
3399  grn_obj casted_min, casted_number;
3400  int i;
3401 
3402  min = GRN_PROC_ALLOC(GRN_DB_VOID, 0);
3403  if (!min) {
3404  return min;
3405  }
3406 
3407  GRN_VOID_INIT(&casted_min);
3408  GRN_VOID_INIT(&casted_number);
3409  for (i = 0; i < nargs; i++) {
3410  grn_obj *number = args[i];
3411  grn_id domain = number->header.domain;
3412  if (!is_comparable_number_type(domain)) {
3413  continue;
3414  }
3415  cast_type = smaller_number_type(cast_type, domain);
3416  if (!number_safe_cast(ctx, number, &casted_number, cast_type)) {
3417  continue;
3418  }
3419  if (min->header.domain == GRN_DB_VOID) {
3420  grn_obj_reinit(ctx, min, cast_type, 0);
3421  GRN_TEXT_SET(ctx, min,
3422  GRN_TEXT_VALUE(&casted_number),
3423  GRN_TEXT_LEN(&casted_number));
3424  continue;
3425  }
3426 
3427  if (min->header.domain != cast_type) {
3428  if (!number_safe_cast(ctx, min, &casted_min, cast_type)) {
3429  continue;
3430  }
3431  grn_obj_reinit(ctx, min, cast_type, 0);
3432  GRN_TEXT_SET(ctx, min,
3433  GRN_TEXT_VALUE(&casted_min),
3434  GRN_TEXT_LEN(&casted_min));
3435  }
3436  if (compare_number(ctx, &casted_number, min, cast_type) < 0) {
3437  grn_obj_reinit(ctx, min, cast_type, 0);
3438  GRN_TEXT_SET(ctx, min,
3439  GRN_TEXT_VALUE(&casted_number),
3440  GRN_TEXT_LEN(&casted_number));
3441  }
3442  }
3443  GRN_OBJ_FIN(ctx, &casted_min);
3444  GRN_OBJ_FIN(ctx, &casted_number);
3445 
3446  return min;
3447 }
3448 
3449 static grn_obj *
3450 func_geo_in_circle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3451 {
3452  grn_obj *obj;
3453  unsigned char r = GRN_FALSE;
3455  switch (nargs) {
3456  case 4 :
3457  if (grn_geo_resolve_approximate_type(ctx, args[3], &type) != GRN_SUCCESS) {
3458  break;
3459  }
3460  /* fallthru */
3461  case 3 :
3462  r = grn_geo_in_circle(ctx, args[0], args[1], args[2], type);
3463  break;
3464  default :
3465  break;
3466  }
3467  if ((obj = GRN_PROC_ALLOC(GRN_DB_UINT32, 0))) {
3468  GRN_UINT32_SET(ctx, obj, r);
3469  }
3470  return obj;
3471 }
3472 
3473 static grn_obj *
3474 func_geo_in_rectangle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3475 {
3476  grn_obj *obj;
3477  unsigned char r = GRN_FALSE;
3478  if (nargs == 3) {
3479  r = grn_geo_in_rectangle(ctx, args[0], args[1], args[2]);
3480  }
3481  if ((obj = GRN_PROC_ALLOC(GRN_DB_UINT32, 0))) {
3482  GRN_UINT32_SET(ctx, obj, r);
3483  }
3484  return obj;
3485 }
3486 
3487 static grn_obj *
3488 func_geo_distance(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3489 {
3490  grn_obj *obj;
3491  double d = 0.0;
3493  switch (nargs) {
3494  case 3 :
3495  if (grn_geo_resolve_approximate_type(ctx, args[2], &type) != GRN_SUCCESS) {
3496  break;
3497  }
3498  /* fallthru */
3499  case 2 :
3500  d = grn_geo_distance(ctx, args[0], args[1], type);
3501  break;
3502  default:
3503  break;
3504  }
3505  if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
3506  GRN_FLOAT_SET(ctx, obj, d);
3507  }
3508  return obj;
3509 }
3510 
3511 /* deprecated. */
3512 static grn_obj *
3513 func_geo_distance2(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3514 {
3515  grn_obj *obj;
3516  double d = 0;
3517  if (nargs == 2) {
3518  d = grn_geo_distance_sphere(ctx, args[0], args[1]);
3519  }
3520  if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
3521  GRN_FLOAT_SET(ctx, obj, d);
3522  }
3523  return obj;
3524 }
3525 
3526 /* deprecated. */
3527 static grn_obj *
3528 func_geo_distance3(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3529 {
3530  grn_obj *obj;
3531  double d = 0;
3532  if (nargs == 2) {
3533  d = grn_geo_distance_ellipsoid(ctx, args[0], args[1]);
3534  }
3535  if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
3536  GRN_FLOAT_SET(ctx, obj, d);
3537  }
3538  return obj;
3539 }
3540 
3541 #define DIST(ox,oy) (dists[((lx + 1) * (oy)) + (ox)])
3542 
3543 static grn_obj *
3544 func_edit_distance(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3545 {
3546  int d = 0;
3547  grn_obj *obj;
3548  if (nargs == 2) {
3549  uint32_t cx, lx, cy, ly, *dists;
3550  char *px, *sx = GRN_TEXT_VALUE(args[0]), *ex = GRN_BULK_CURR(args[0]);
3551  char *py, *sy = GRN_TEXT_VALUE(args[1]), *ey = GRN_BULK_CURR(args[1]);
3552  for (px = sx, lx = 0; px < ex && (cx = grn_charlen(ctx, px, ex)); px += cx, lx++);
3553  for (py = sy, ly = 0; py < ey && (cy = grn_charlen(ctx, py, ey)); py += cy, ly++);
3554  if ((dists = GRN_MALLOC((lx + 1) * (ly + 1) * sizeof(uint32_t)))) {
3555  uint32_t x, y;
3556  for (x = 0; x <= lx; x++) { DIST(x, 0) = x; }
3557  for (y = 0; y <= ly; y++) { DIST(0, y) = y; }
3558  for (x = 1, px = sx; x <= lx; x++, px += cx) {
3559  cx = grn_charlen(ctx, px, ex);
3560  for (y = 1, py = sy; y <= ly; y++, py += cy) {
3561  cy = grn_charlen(ctx, py, ey);
3562  if (cx == cy && !memcmp(px, py, cx)) {
3563  DIST(x, y) = DIST(x - 1, y - 1);
3564  } else {
3565  uint32_t a = DIST(x - 1, y) + 1;
3566  uint32_t b = DIST(x, y - 1) + 1;
3567  uint32_t c = DIST(x - 1, y - 1) + 1;
3568  DIST(x, y) = ((a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c));
3569  }
3570  }
3571  }
3572  d = DIST(lx, ly);
3573  GRN_FREE(dists);
3574  }
3575  }
3576  if ((obj = GRN_PROC_ALLOC(GRN_DB_UINT32, 0))) {
3577  GRN_UINT32_SET(ctx, obj, d);
3578  }
3579  return obj;
3580 }
3581 
3582 static grn_obj *
3583 func_all_records(grn_ctx *ctx, int nargs, grn_obj **args,
3584  grn_user_data *user_data)
3585 {
3586  grn_obj *true_value;
3587  if ((true_value = GRN_PROC_ALLOC(GRN_DB_BOOL, 0))) {
3588  GRN_BOOL_SET(ctx, true_value, GRN_TRUE);
3589  }
3590  return true_value;
3591 }
3592 
3593 static grn_rc
3594 selector_all_records(grn_ctx *ctx, grn_obj *table, grn_obj *index,
3595  int nargs, grn_obj **args,
3596  grn_obj *res, grn_operator op)
3597 {
3598  grn_obj score;
3599 
3600  GRN_UINT32_INIT(&score, 0);
3601  GRN_UINT32_SET(ctx, &score, 1);
3602 
3603  GRN_TABLE_EACH(ctx, table, 0, 0, id, NULL, NULL, NULL, {
3604  grn_id result_id;
3605  result_id = grn_table_add(ctx, res, &id, sizeof(grn_id), NULL);
3606  grn_obj_set_value(ctx, res, result_id, &score, GRN_OBJ_SET);
3607  });
3608 
3609  GRN_OBJ_FIN(ctx, &score);
3610 
3611  return ctx->rc;
3612 }
3613 
3614 static grn_obj *
3615 func_snippet_html(grn_ctx *ctx, int nargs, grn_obj **args,
3616  grn_user_data *user_data)
3617 {
3618  grn_obj *snippets;
3619 
3621  if (!snippets) {
3622  return NULL;
3623  }
3624 
3625  /* TODO: support parameters */
3626  if (nargs == 1) {
3627  grn_obj *text = args[0];
3628  grn_obj *expression = NULL;
3629  grn_obj *condition_ptr = NULL;
3630  grn_obj *condition = NULL;
3631  grn_snip *snip = NULL;
3633  unsigned int width = 200;
3634  unsigned int max_n_results = 3;
3635  unsigned int n_tags = 1;
3636  const char *open_tags[] = {"<span class=\"keyword\">"};
3637  unsigned int open_tag_lengths[1];
3638  const char *close_tags[] = {"</span>"};
3639  unsigned int close_tag_lengths[1];
3641 
3642  open_tag_lengths[0] = strlen(open_tags[0]);
3643  close_tag_lengths[0] = strlen(close_tags[0]);
3644 
3645  grn_proc_get_info(ctx, user_data, NULL, NULL, &expression);
3646  condition_ptr = grn_expr_get_var(ctx, expression,
3649  if (condition_ptr) {
3650  condition = GRN_PTR_VALUE(condition_ptr);
3651  }
3652 
3653  if (condition) {
3654  snip = grn_expr_snip(ctx, condition, flags,
3655  width, max_n_results, n_tags,
3656  open_tags, open_tag_lengths,
3657  close_tags, close_tag_lengths,
3658  mapping);
3659  }
3660 
3661  if (snip) {
3662  grn_rc rc;
3663  unsigned int i, n_results, max_tagged_length;
3664  grn_obj snippet_buffer;
3665 
3666  rc = grn_snip_exec(ctx, snip,
3667  GRN_TEXT_VALUE(text), GRN_TEXT_LEN(text),
3668  &n_results, &max_tagged_length);
3669  GRN_TEXT_INIT(&snippet_buffer, 0);
3670  grn_bulk_space(ctx, &snippet_buffer, max_tagged_length);
3671  for (i = 0; i < n_results; i++) {
3672  unsigned int snippet_length;
3673 
3674  GRN_BULK_REWIND(&snippet_buffer);
3675  rc = grn_snip_get_result(ctx, snip, i,
3676  GRN_TEXT_VALUE(&snippet_buffer),
3677  &snippet_length);
3678  grn_vector_add_element(ctx, snippets,
3679  GRN_TEXT_VALUE(&snippet_buffer), snippet_length,
3680  0, GRN_DB_SHORT_TEXT);
3681  }
3682  GRN_OBJ_FIN(ctx, &snippet_buffer);
3683  grn_snip_close(ctx, snip);
3684  }
3685  }
3686 
3687  return snippets;
3688 }
3689 
3690 static grn_rc
3691 run_query(grn_ctx *ctx, grn_obj *table,
3692  int nargs, grn_obj **args,
3693  grn_obj *res, grn_operator op)
3694 {
3695  grn_rc rc = GRN_SUCCESS;
3696  grn_obj *match_columns_string;
3697  grn_obj *query;
3698  grn_obj *query_expander_name = NULL;
3699  grn_obj *match_columns = NULL;
3700  grn_obj *condition = NULL;
3701  grn_obj *dummy_variable;
3702 
3703  /* TODO: support flags by parameters */
3704  if (!(2 <= nargs && nargs <= 3)) {
3706  "wrong number of arguments (%d for 2..3)", nargs);
3707  rc = ctx->rc;
3708  goto exit;
3709  }
3710 
3711  match_columns_string = args[0];
3712  query = args[1];
3713  if (nargs > 2) {
3714  query_expander_name = args[2];
3715  }
3716 
3717  if (match_columns_string->header.domain == GRN_DB_TEXT &&
3718  GRN_TEXT_LEN(match_columns_string) > 0) {
3719  GRN_EXPR_CREATE_FOR_QUERY(ctx, table, match_columns, dummy_variable);
3720  if (!match_columns) {
3721  rc = ctx->rc;
3722  goto exit;
3723  }
3724 
3725  grn_expr_parse(ctx, match_columns,
3726  GRN_TEXT_VALUE(match_columns_string),
3727  GRN_TEXT_LEN(match_columns_string),
3728  NULL, GRN_OP_MATCH, GRN_OP_AND,
3730  if (ctx->rc != GRN_SUCCESS) {
3731  rc = ctx->rc;
3732  goto exit;
3733  }
3734  }
3735 
3736  if (query->header.domain == GRN_DB_TEXT && GRN_TEXT_LEN(query) > 0) {
3737  const char *query_string;
3738  unsigned int query_string_len;
3739  grn_obj expanded_query;
3740  grn_expr_flags flags =
3742 
3743  GRN_EXPR_CREATE_FOR_QUERY(ctx, table, condition, dummy_variable);
3744  if (!condition) {
3745  rc = ctx->rc;
3746  goto exit;
3747  }
3748 
3749  query_string = GRN_TEXT_VALUE(query);
3750  query_string_len = GRN_TEXT_LEN(query);
3751 
3752  GRN_TEXT_INIT(&expanded_query, 0);
3753  if (query_expander_name &&
3754  query_expander_name->header.domain == GRN_DB_TEXT &&
3755  GRN_TEXT_LEN(query_expander_name) > 0) {
3756  rc = expand_query(ctx, query_string, query_string_len, flags,
3757  GRN_TEXT_VALUE(query_expander_name),
3758  GRN_TEXT_LEN(query_expander_name),
3759  &expanded_query);
3760  if (rc != GRN_SUCCESS) {
3761  GRN_OBJ_FIN(ctx, &expanded_query);
3762  goto exit;
3763  }
3764  query_string = GRN_TEXT_VALUE(&expanded_query);
3765  query_string_len = GRN_TEXT_LEN(&expanded_query);
3766  }
3767  grn_expr_parse(ctx, condition,
3768  query_string,
3769  query_string_len,
3770  match_columns, GRN_OP_MATCH, GRN_OP_AND, flags);
3771  rc = ctx->rc;
3772  GRN_OBJ_FIN(ctx, &expanded_query);
3773  if (rc != GRN_SUCCESS) {
3774  goto exit;
3775  }
3776  grn_table_select(ctx, table, condition, res, op);
3777  rc = ctx->rc;
3778  }
3779 
3780 exit:
3781  if (match_columns) {
3782  grn_obj_unlink(ctx, match_columns);
3783  }
3784  if (condition) {
3785  grn_obj_unlink(ctx, condition);
3786  }
3787 
3788  return rc;
3789 }
3790 
3791 static grn_obj *
3792 func_query(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3793 {
3794  grn_obj *found;
3795  grn_obj *condition = NULL;
3796  grn_obj *variable;
3797  grn_obj *table = NULL;
3798  grn_obj *res = NULL;
3799 
3800  found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
3801  if (!found) {
3802  goto exit;
3803  }
3804  GRN_BOOL_SET(ctx, found, GRN_FALSE);
3805 
3806  grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
3807  if (!condition) {
3808  goto exit;
3809  }
3810 
3811  variable = grn_expr_get_var_by_offset(ctx, condition, 0);
3812  if (!variable) {
3813  goto exit;
3814  }
3815 
3816  table = grn_ctx_at(ctx, variable->header.domain);
3817  if (!table) {
3818  goto exit;
3819  }
3820 
3821  res = grn_table_create(ctx, NULL, 0, NULL,
3823  if (!res) {
3824  goto exit;
3825  }
3826  {
3827  grn_rset_posinfo pi;
3828  unsigned int key_size;
3829  memset(&pi, 0, sizeof(grn_rset_posinfo));
3830  pi.rid = GRN_RECORD_VALUE(variable);
3831  key_size = ((grn_hash *)res)->key_size;
3832  if (grn_table_add(ctx, res, &pi, key_size, NULL) == GRN_ID_NIL) {
3833  goto exit;
3834  }
3835  }
3836  if (run_query(ctx, table, nargs, args, res, GRN_OP_AND) == GRN_SUCCESS) {
3837  GRN_BOOL_SET(ctx, found, grn_table_size(ctx, res) > 0);
3838  }
3839 
3840 exit:
3841  if (res) {
3842  grn_obj_unlink(ctx, res);
3843  }
3844  if (table) {
3845  grn_obj_unlink(ctx, table);
3846  }
3847 
3848  return found;
3849 }
3850 
3851 static grn_rc
3852 selector_query(grn_ctx *ctx, grn_obj *table, grn_obj *index,
3853  int nargs, grn_obj **args,
3854  grn_obj *res, grn_operator op)
3855 {
3856  return run_query(ctx, table, nargs - 1, args + 1, res, op);
3857 }
3858 
3859 static grn_rc
3860 run_sub_filter(grn_ctx *ctx, grn_obj *table,
3861  int nargs, grn_obj **args,
3862  grn_obj *res, grn_operator op)
3863 {
3864  grn_rc rc = GRN_SUCCESS;
3865  grn_obj *scope;
3866  grn_obj *sub_filter_string;
3867  grn_obj *scope_domain = NULL;
3868  grn_obj *sub_filter = NULL;
3869  grn_obj *dummy_variable = NULL;
3870 
3871  if (nargs != 2) {
3873  "sub_filter(): wrong number of arguments (%d for 2)", nargs);
3874  rc = ctx->rc;
3875  goto exit;
3876  }
3877 
3878  scope = args[0];
3879  sub_filter_string = args[1];
3880 
3881  switch (scope->header.type) {
3882  case GRN_ACCESSOR :
3883  case GRN_COLUMN_FIX_SIZE :
3884  case GRN_COLUMN_VAR_SIZE :
3885  break;
3886  default :
3887  /* TODO: put inspected the 1nd argument to message */
3889  "sub_filter(): the 1nd argument must be column or accessor");
3890  rc = ctx->rc;
3891  goto exit;
3892  break;
3893  }
3894 
3895  scope_domain = grn_ctx_at(ctx, grn_obj_get_range(ctx, scope));
3896 
3897  if (sub_filter_string->header.domain != GRN_DB_TEXT) {
3898  /* TODO: put inspected the 2nd argument to message */
3900  "sub_filter(): the 2nd argument must be String");
3901  rc = ctx->rc;
3902  goto exit;
3903  }
3904  if (GRN_TEXT_LEN(sub_filter_string) == 0) {
3906  "sub_filter(): the 2nd argument must not be empty String");
3907  rc = ctx->rc;
3908  goto exit;
3909  }
3910 
3911  GRN_EXPR_CREATE_FOR_QUERY(ctx, scope_domain, sub_filter, dummy_variable);
3912  if (!sub_filter) {
3913  rc = ctx->rc;
3914  goto exit;
3915  }
3916 
3917  grn_expr_parse(ctx, sub_filter,
3918  GRN_TEXT_VALUE(sub_filter_string),
3919  GRN_TEXT_LEN(sub_filter_string),
3920  NULL, GRN_OP_MATCH, GRN_OP_AND,
3922  if (ctx->rc != GRN_SUCCESS) {
3923  rc = ctx->rc;
3924  goto exit;
3925  }
3926 
3927  {
3928  grn_obj *base_res = NULL;
3929 
3930  base_res = grn_table_create(ctx, NULL, 0, NULL,
3932  scope_domain, NULL);
3933  grn_table_select(ctx, scope_domain, sub_filter, base_res, GRN_OP_OR);
3934  if (scope->header.type == GRN_ACCESSOR) {
3935  rc = grn_accessor_resolve(ctx, scope, -1, base_res, res, op, NULL);
3936  } else {
3937  grn_accessor accessor;
3938  accessor.header.type = GRN_ACCESSOR;
3939  accessor.obj = scope;
3941  accessor.next = NULL;
3942  rc = grn_accessor_resolve(ctx, (grn_obj *)&accessor, -1, base_res,
3943  res, op, NULL);
3944  }
3945  grn_obj_unlink(ctx, base_res);
3946  }
3947 
3948 exit:
3949  if (scope_domain) {
3950  grn_obj_unlink(ctx, scope_domain);
3951  }
3952  if (sub_filter) {
3953  grn_obj_unlink(ctx, sub_filter);
3954  }
3955 
3956  return rc;
3957 }
3958 
3959 static grn_obj *
3960 func_sub_filter(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
3961 {
3962  grn_obj *found;
3963  grn_obj *condition = NULL;
3964  grn_obj *variable;
3965  grn_obj *table = NULL;
3966  grn_obj *res = NULL;
3967 
3968  found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
3969  if (!found) {
3970  goto exit;
3971  }
3972  GRN_BOOL_SET(ctx, found, GRN_FALSE);
3973 
3974  grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
3975  if (!condition) {
3976  goto exit;
3977  }
3978 
3979  variable = grn_expr_get_var_by_offset(ctx, condition, 0);
3980  if (!variable) {
3981  goto exit;
3982  }
3983 
3984  table = grn_ctx_at(ctx, variable->header.domain);
3985  if (!table) {
3986  goto exit;
3987  }
3988 
3989  res = grn_table_create(ctx, NULL, 0, NULL,
3991  if (!res) {
3992  goto exit;
3993  }
3994  {
3995  grn_rset_posinfo pi;
3996  unsigned int key_size;
3997  memset(&pi, 0, sizeof(grn_rset_posinfo));
3998  pi.rid = GRN_RECORD_VALUE(variable);
3999  key_size = ((grn_hash *)res)->key_size;
4000  if (grn_table_add(ctx, res, &pi, key_size, NULL) == GRN_ID_NIL) {
4001  goto exit;
4002  }
4003  }
4004  if (run_sub_filter(ctx, table, nargs, args, res, GRN_OP_AND) == GRN_SUCCESS) {
4005  GRN_BOOL_SET(ctx, found, grn_table_size(ctx, res) > 0);
4006  }
4007 
4008 exit:
4009  if (res) {
4010  grn_obj_unlink(ctx, res);
4011  }
4012  if (table) {
4013  grn_obj_unlink(ctx, table);
4014  }
4015 
4016  return found;
4017 }
4018 
4019 static grn_rc
4020 selector_sub_filter(grn_ctx *ctx, grn_obj *table, grn_obj *index,
4021  int nargs, grn_obj **args,
4022  grn_obj *res, grn_operator op)
4023 {
4024  return run_sub_filter(ctx, table, nargs - 1, args + 1, res, op);
4025 }
4026 
4027 static grn_obj *
4028 func_html_untag(grn_ctx *ctx, int nargs, grn_obj **args,
4029  grn_user_data *user_data)
4030 {
4031  grn_obj *html_arg;
4032  int html_arg_domain;
4033  grn_obj html;
4034  grn_obj *text;
4035  const char *html_raw;
4036  int i, length;
4037  grn_bool in_tag = GRN_FALSE;
4038 
4039  if (nargs != 1) {
4040  ERR(GRN_INVALID_ARGUMENT, "HTML is missing");
4041  return NULL;
4042  }
4043 
4044  html_arg = args[0];
4045  html_arg_domain = html_arg->header.domain;
4046  switch (html_arg_domain) {
4047  case GRN_DB_SHORT_TEXT :
4048  case GRN_DB_TEXT :
4049  case GRN_DB_LONG_TEXT :
4050  GRN_VALUE_VAR_SIZE_INIT(&html, GRN_OBJ_DO_SHALLOW_COPY, html_arg_domain);
4051  GRN_TEXT_SET(ctx, &html, GRN_TEXT_VALUE(html_arg), GRN_TEXT_LEN(html_arg));
4052  break;
4053  default :
4054  GRN_TEXT_INIT(&html, 0);
4055  if (grn_obj_cast(ctx, html_arg, &html, GRN_FALSE)) {
4056  grn_obj inspected;
4057  GRN_TEXT_INIT(&inspected, 0);
4058  grn_inspect(ctx, &inspected, html_arg);
4059  ERR(GRN_INVALID_ARGUMENT, "failed to cast to text: <%.*s>",
4060  (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
4061  GRN_OBJ_FIN(ctx, &inspected);
4062  GRN_OBJ_FIN(ctx, &html);
4063  return NULL;
4064  }
4065  break;
4066  }
4067 
4068  text = GRN_PROC_ALLOC(html.header.domain, 0);
4069  if (!text) {
4070  GRN_OBJ_FIN(ctx, &html);
4071  return NULL;
4072  }
4073 
4074  html_raw = GRN_TEXT_VALUE(&html);
4075  length = GRN_TEXT_LEN(&html);
4076  for (i = 0; i < length; i++) {
4077  switch (html_raw[i]) {
4078  case '<' :
4079  in_tag = GRN_TRUE;
4080  break;
4081  case '>' :
4082  if (in_tag) {
4083  in_tag = GRN_FALSE;
4084  } else {
4085  GRN_TEXT_PUTC(ctx, text, html_raw[i]);
4086  }
4087  break;
4088  default :
4089  if (!in_tag) {
4090  GRN_TEXT_PUTC(ctx, text, html_raw[i]);
4091  }
4092  break;
4093  }
4094  }
4095 
4096  GRN_OBJ_FIN(ctx, &html);
4097 
4098  return text;
4099 }
4100 
4101 #define DEF_VAR(v,name_str) do {\
4102  (v).name = (name_str);\
4103  (v).name_size = GRN_STRLEN(name_str);\
4104  GRN_TEXT_INIT(&(v).value, 0);\
4105 } while (0)
4106 
4107 #define DEF_COMMAND(name, func, nvars, vars)\
4108  (grn_proc_create(ctx, (name), (sizeof(name) - 1),\
4109  GRN_PROC_COMMAND, (func), NULL, NULL, (nvars), (vars)))
4110 
4111 void
4113 {
4114  grn_expr_var vars[20];
4115 
4116  DEF_VAR(vars[0], "name");
4117  DEF_VAR(vars[1], "table");
4118  DEF_VAR(vars[2], "match_columns");
4119  DEF_VAR(vars[3], "query");
4120  DEF_VAR(vars[4], "filter");
4121  DEF_VAR(vars[5], "scorer");
4122  DEF_VAR(vars[6], "sortby");
4123  DEF_VAR(vars[7], "output_columns");
4124  DEF_VAR(vars[8], "offset");
4125  DEF_VAR(vars[9], "limit");
4126  DEF_VAR(vars[10], "drilldown");
4127  DEF_VAR(vars[11], "drilldown_sortby");
4128  DEF_VAR(vars[12], "drilldown_output_columns");
4129  DEF_VAR(vars[13], "drilldown_offset");
4130  DEF_VAR(vars[14], "drilldown_limit");
4131  DEF_VAR(vars[15], "cache");
4132  DEF_VAR(vars[16], "match_escalation_threshold");
4133  /* Deprecated. Use query_expander instead. */
4134  DEF_VAR(vars[17], "query_expansion");
4135  DEF_VAR(vars[18], "query_flags");
4136  DEF_VAR(vars[19], "query_expander");
4137  DEF_COMMAND("define_selector", proc_define_selector, 20, vars);
4138  DEF_COMMAND("select", proc_select, 19, vars + 1);
4139 
4140  DEF_VAR(vars[0], "values");
4141  DEF_VAR(vars[1], "table");
4142  DEF_VAR(vars[2], "columns");
4143  DEF_VAR(vars[3], "ifexists");
4144  DEF_VAR(vars[4], "input_type");
4145  DEF_VAR(vars[5], "each");
4146  DEF_COMMAND("load", proc_load, 6, vars);
4147 
4148  DEF_COMMAND("status", proc_status, 0, vars);
4149 
4150  DEF_COMMAND("table_list", proc_table_list, 0, vars);
4151 
4152  DEF_VAR(vars[0], "table");
4153  DEF_COMMAND("column_list", proc_column_list, 1, vars);
4154 
4155  DEF_VAR(vars[0], "name");
4156  DEF_VAR(vars[1], "flags");
4157  DEF_VAR(vars[2], "key_type");
4158  DEF_VAR(vars[3], "value_type");
4159  DEF_VAR(vars[4], "default_tokenizer");
4160  DEF_VAR(vars[5], "normalizer");
4161  DEF_COMMAND("table_create", proc_table_create, 6, vars);
4162 
4163  DEF_VAR(vars[0], "name");
4164  DEF_COMMAND("table_remove", proc_table_remove, 1, vars);
4165 
4166  DEF_VAR(vars[0], "name");
4167  DEF_VAR(vars[1], "new_name");
4168  DEF_COMMAND("table_rename", proc_table_rename, 2, vars);
4169 
4170  DEF_VAR(vars[0], "table");
4171  DEF_VAR(vars[1], "name");
4172  DEF_VAR(vars[2], "flags");
4173  DEF_VAR(vars[3], "type");
4174  DEF_VAR(vars[4], "source");
4175  DEF_COMMAND("column_create", proc_column_create, 5, vars);
4176 
4177  DEF_VAR(vars[0], "table");
4178  DEF_VAR(vars[1], "name");
4179  DEF_COMMAND("column_remove", proc_column_remove, 2, vars);
4180 
4181  DEF_VAR(vars[0], "table");
4182  DEF_VAR(vars[1], "name");
4183  DEF_VAR(vars[2], "new_name");
4184  DEF_COMMAND("column_rename", proc_column_rename, 3, vars);
4185 
4186  DEF_VAR(vars[0], "path");
4187  DEF_COMMAND(GRN_EXPR_MISSING_NAME, proc_missing, 1, vars);
4188 
4189  DEF_COMMAND("quit", proc_quit, 0, vars);
4190 
4191  DEF_COMMAND("shutdown", proc_shutdown, 0, vars);
4192 
4193  DEF_VAR(vars[0], "target_name");
4194  DEF_COMMAND("clearlock", proc_clearlock, 1, vars);
4195 
4196  DEF_VAR(vars[0], "target_name");
4197  DEF_VAR(vars[1], "threshold");
4198  DEF_COMMAND("defrag", proc_defrag, 2, vars);
4199 
4200  DEF_VAR(vars[0], "level");
4201  DEF_COMMAND("log_level", proc_log_level, 1, vars);
4202 
4203  DEF_VAR(vars[0], "level");
4204  DEF_VAR(vars[1], "message");
4205  DEF_COMMAND("log_put", proc_log_put, 2, vars);
4206 
4207  DEF_COMMAND("log_reopen", proc_log_reopen, 0, vars);
4208 
4209  DEF_VAR(vars[0], "table");
4210  DEF_VAR(vars[1], "key");
4211  DEF_VAR(vars[2], "id");
4212  DEF_VAR(vars[3], "filter");
4213  DEF_COMMAND("delete", proc_delete, 4, vars);
4214 
4215  DEF_VAR(vars[0], "max");
4216  DEF_COMMAND("cache_limit", proc_cache_limit, 1, vars);
4217 
4218  DEF_VAR(vars[0], "tables");
4219  DEF_COMMAND("dump", proc_dump, 1, vars);
4220 
4221  DEF_VAR(vars[0], "path");
4222  DEF_COMMAND("register", proc_register, 1, vars);
4223 
4224  DEF_VAR(vars[0], "obj");
4225  DEF_COMMAND("check", proc_check, 1, vars);
4226 
4227  DEF_VAR(vars[0], "table");
4228  DEF_COMMAND("truncate", proc_truncate, 1, vars);
4229 
4230  DEF_VAR(vars[0], "normalizer");
4231  DEF_VAR(vars[1], "string");
4232  DEF_VAR(vars[2], "flags");
4233  DEF_COMMAND("normalize", proc_normalize, 3, vars);
4234 
4235  DEF_VAR(vars[0], "tokenizer");
4236  DEF_VAR(vars[1], "string");
4237  DEF_VAR(vars[2], "normalizer");
4238  DEF_VAR(vars[3], "flags");
4239  DEF_COMMAND("tokenize", proc_tokenize, 4, vars);
4240 
4241  DEF_VAR(vars[0], "seed");
4242  grn_proc_create(ctx, "rand", -1, GRN_PROC_FUNCTION, func_rand,
4243  NULL, NULL, 0, vars);
4244 
4245  grn_proc_create(ctx, "now", -1, GRN_PROC_FUNCTION, func_now,
4246  NULL, NULL, 0, vars);
4247 
4248  grn_proc_create(ctx, "max", -1, GRN_PROC_FUNCTION, func_max,
4249  NULL, NULL, 0, vars);
4250  grn_proc_create(ctx, "min", -1, GRN_PROC_FUNCTION, func_min,
4251  NULL, NULL, 0, vars);
4252 
4253  {
4254  grn_obj *selector_proc;
4255 
4256  selector_proc = grn_proc_create(ctx, "geo_in_circle", -1, GRN_PROC_FUNCTION,
4257  func_geo_in_circle, NULL, NULL, 0, NULL);
4259 
4260  selector_proc = grn_proc_create(ctx, "geo_in_rectangle", -1,
4262  func_geo_in_rectangle, NULL, NULL, 0, NULL);
4264  }
4265 
4266  grn_proc_create(ctx, "geo_distance", -1, GRN_PROC_FUNCTION,
4267  func_geo_distance, NULL, NULL, 0, NULL);
4268 
4269  /* deprecated. */
4270  grn_proc_create(ctx, "geo_distance2", -1, GRN_PROC_FUNCTION,
4271  func_geo_distance2, NULL, NULL, 0, NULL);
4272 
4273  /* deprecated. */
4274  grn_proc_create(ctx, "geo_distance3", -1, GRN_PROC_FUNCTION,
4275  func_geo_distance3, NULL, NULL, 0, NULL);
4276 
4277  grn_proc_create(ctx, "edit_distance", -1, GRN_PROC_FUNCTION,
4278  func_edit_distance, NULL, NULL, 0, NULL);
4279 
4280  {
4281  grn_obj *selector_proc;
4282 
4283  selector_proc = grn_proc_create(ctx, "all_records", -1, GRN_PROC_FUNCTION,
4284  func_all_records, NULL, NULL, 0, NULL);
4285  grn_proc_set_selector(ctx, selector_proc, selector_all_records);
4286  }
4287 
4288  /* experimental */
4289  grn_proc_create(ctx, "snippet_html", -1, GRN_PROC_FUNCTION,
4290  func_snippet_html, NULL, NULL, 0, NULL);
4291 
4292  {
4293  grn_obj *selector_proc;
4294 
4295  selector_proc = grn_proc_create(ctx, "query", -1, GRN_PROC_FUNCTION,
4296  func_query, NULL, NULL, 0, NULL);
4297  grn_proc_set_selector(ctx, selector_proc, selector_query);
4298  }
4299 
4300  {
4301  grn_obj *selector_proc;
4302 
4303  selector_proc = grn_proc_create(ctx, "sub_filter", -1, GRN_PROC_FUNCTION,
4304  func_sub_filter, NULL, NULL, 0, NULL);
4305  grn_proc_set_selector(ctx, selector_proc, selector_sub_filter);
4306  }
4307 
4308  grn_proc_create(ctx, "html_untag", -1, GRN_PROC_FUNCTION,
4309  func_html_untag, NULL, NULL, 0, NULL);
4310 }