Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
db.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2 -*- */
2 /* Copyright(C) 2009-2013 Brazil
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License version 2.1 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Lesser General Public License for more details.
12 
13  You should have received a copy of the GNU Lesser General Public
14  License along with this library; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 #include "groonga_in.h"
18 #include "db.h"
19 #include "hash.h"
20 #include "pat.h"
21 #include "dat.h"
22 #include "ii.h"
23 #include "ctx_impl.h"
24 #include "token.h"
25 #include "proc.h"
26 #include "plugin_in.h"
27 #include "geo.h"
28 #include "snip.h"
29 #include "string_in.h"
30 #include "normalizer_in.h"
31 #include "util.h"
32 #include <string.h>
33 #include <float.h>
34 
35 #define NEXT_ADDR(p) (((byte *)(p)) + sizeof(*(p)))
36 
37 #define GRN_TABLE_GROUPED (0x01<<0)
38 #define GRN_TABLE_IS_GROUPED(table)\
39  ((table)->header.impl_flags & GRN_TABLE_GROUPED)
40 #define GRN_TABLE_GROUPED_ON(table)\
41  ((table)->header.impl_flags |= GRN_TABLE_GROUPED)
42 
43 #define WITH_NORMALIZE(table,key,key_size,block) do {\
44  if ((table)->normalizer && key && key_size > 0) {\
45  grn_obj *nstr;\
46  if ((nstr = grn_string_open(ctx, key, key_size,\
47  (table)->normalizer, 0))) {\
48  const char *key;\
49  unsigned int key_size;\
50  grn_string_get_normalized(ctx, nstr, &key, &key_size, NULL);\
51  block\
52  grn_obj_close(ctx, nstr);\
53  }\
54  } else {\
55  block\
56  }\
57 } while (0)
58 
59 #define REPORT_CAST_ERROR(column, range, element) do {\
60  grn_obj inspected;\
61  char column_name[GRN_TABLE_MAX_KEY_SIZE];\
62  int column_name_size;\
63  char range_name[GRN_TABLE_MAX_KEY_SIZE];\
64  int range_name_size;\
65  GRN_TEXT_INIT(&inspected, 0);\
66  grn_inspect(ctx, &inspected, element);\
67  column_name_size = grn_obj_name(ctx, column, column_name,\
68  GRN_TABLE_MAX_KEY_SIZE);\
69  range_name_size = grn_obj_name(ctx, range, range_name,\
70  GRN_TABLE_MAX_KEY_SIZE);\
71  ERR(GRN_INVALID_ARGUMENT, "<%.*s>: failed to cast to <%.*s>: <%.*s>",\
72  column_name_size, column_name,\
73  range_name_size, range_name,\
74  (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));\
75  GRN_OBJ_FIN(ctx, &inspected);\
76 } while (0)
77 
78 inline static grn_id
79 grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
80  void **value, int *added);
81 inline static void
82 grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, int score,
83  grn_rset_posinfo *pi, int dir);
84 inline static grn_id
85 grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc);
86 inline static int
87 grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value);
88 
89 static void grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj);
90 static void grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj);
91 
92 inline static void
93 gen_pathname(const char *path, char *buffer, int fno)
94 {
95  size_t len = strlen(path);
96  memcpy(buffer, path, len);
97  if (fno >= 0) {
98  buffer[len] = '.';
99  grn_itoh(fno, buffer + len + 1, 7);
100  buffer[len + 8] = '\0';
101  } else {
102  buffer[len] = '\0';
103  }
104 }
105 
106 static grn_bool
107 is_text_object(grn_obj *object)
108 {
109  if (!object) {
110  return GRN_FALSE;
111  }
112 
113  if (object->header.type != GRN_BULK) {
114  return GRN_FALSE;
115  }
116 
117  switch (object->header.domain) {
118  case GRN_DB_SHORT_TEXT:
119  case GRN_DB_TEXT:
120  case GRN_DB_LONG_TEXT:
121  return GRN_TRUE;
122  default:
123  return GRN_FALSE;
124  }
125 }
126 
127 static void
128 limited_size_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *object)
129 {
130  unsigned int original_size = 0;
131  unsigned int max_size = GRN_CTX_MSGSIZE / 2;
132 
133  if (object) {
134  original_size = GRN_BULK_VSIZE(object);
135  }
136 
137  if (original_size > max_size && is_text_object(object)) {
138  grn_text_esc(ctx, buffer, GRN_TEXT_VALUE(object), max_size);
139  GRN_TEXT_PUTS(ctx, buffer, "...(");
140  grn_text_lltoa(ctx, buffer, original_size);
141  GRN_TEXT_PUTS(ctx, buffer, ")");
142  } else {
143  grn_inspect(ctx, buffer, object);
144  }
145 }
146 
147 typedef struct {
149  uint32_t lock;
150  uint32_t done;
151 } db_value;
152 
153 grn_obj *
154 grn_db_create(grn_ctx *ctx, const char *path, grn_db_create_optarg *optarg)
155 {
156  grn_db *s;
158  if (!path || strlen(path) <= PATH_MAX - 14) {
159  if ((s = GRN_MALLOC(sizeof(grn_db)))) {
160  grn_bool use_default_db_key = GRN_TRUE;
161  grn_bool use_pat_as_db_keys = GRN_FALSE;
162  if (getenv("GRN_DB_KEY")) {
163  if (!strcmp(getenv("GRN_DB_KEY"), "pat")) {
164  use_default_db_key = GRN_FALSE;
165  use_pat_as_db_keys = GRN_TRUE;
166  } else if (!strcmp(getenv("GRN_DB_KEY"), "dat")) {
167  use_default_db_key = GRN_FALSE;
168  }
169  }
170  if (use_default_db_key && !strcmp(GRN_DEFAULT_DB_KEY, "pat")) {
171  use_pat_as_db_keys = GRN_TRUE;
172  }
173  grn_tiny_array_init(ctx, &s->values, sizeof(db_value),
177  if (use_pat_as_db_keys) {
180  } else {
183  }
184  if (s->keys) {
185  CRITICAL_SECTION_INIT(s->lock);
187  s->obj.db = (grn_obj *)s;
189  DB_OBJ(&s->obj)->range = GRN_ID_NIL;
190  // prepare builtin classes and load builtin plugins.
191  if (path) {
192  char specs_path[PATH_MAX];
193  gen_pathname(path, specs_path, 0);
194  if ((s->specs = grn_ja_create(ctx, specs_path, 65536, 0))) {
195  grn_ctx_use(ctx, (grn_obj *)s);
197  GRN_API_RETURN((grn_obj *)s);
198  } else {
200  "failed to create specs: <%s>", specs_path);
201  }
202  } else {
203  s->specs = NULL;
204  grn_ctx_use(ctx, (grn_obj *)s);
206  GRN_API_RETURN((grn_obj *)s);
207  }
208  if (use_pat_as_db_keys) {
209  grn_pat_close(ctx, (grn_pat *)s->keys);
210  grn_pat_remove(ctx, path);
211  } else {
212  grn_dat_close(ctx, (grn_dat *)s->keys);
213  grn_dat_remove(ctx, path);
214  }
215  }
217  GRN_FREE(s);
218  } else {
219  ERR(GRN_NO_MEMORY_AVAILABLE, "grn_db alloc failed");
220  }
221  } else {
222  ERR(GRN_INVALID_ARGUMENT, "too long path");
223  }
224  GRN_API_RETURN(NULL);
225 }
226 
227 grn_obj *
228 grn_db_open(grn_ctx *ctx, const char *path)
229 {
230  grn_db *s;
231  grn_ctx *ctx_ = ctx;
233  if (path && strlen(path) <= PATH_MAX - 14) {
234  if ((s = GRN_MALLOC(sizeof(grn_db)))) {
235  uint32_t type = grn_io_detect_type(ctx, path);
236  grn_tiny_array_init(ctx, &s->values, sizeof(db_value),
240  switch (type) {
241  case GRN_TABLE_PAT_KEY :
242  s->keys = (grn_obj *)grn_pat_open(ctx, path);
243  break;
244  case GRN_TABLE_DAT_KEY :
245  s->keys = (grn_obj *)grn_dat_open(ctx, path);
246  break;
247  default :
248  s->keys = NULL;
249  break;
250  }
251  if (s->keys) {
252  char specs_path[PATH_MAX];
253  gen_pathname(path, specs_path, 0);
254  if ((s->specs = grn_ja_open(ctx, specs_path))) {
255  CRITICAL_SECTION_INIT(s->lock);
257  s->obj.db = (grn_obj *)s;
259  DB_OBJ(&s->obj)->range = GRN_ID_NIL;
260  grn_ctx_use(ctx, (grn_obj *)s);
261  grn_ctx_use(ctx_, (grn_obj *)s);
262 #ifdef GRN_WITH_MECAB
263  if (grn_db_init_mecab_tokenizer(ctx)) {
264  ERRCLR(ctx);
265  }
266 #endif
270  GRN_API_RETURN((grn_obj *)s);
271  }
272  switch (type) {
273  case GRN_TABLE_PAT_KEY :
274  grn_pat_close(ctx, (grn_pat *)s->keys);
275  break;
276  case GRN_TABLE_DAT_KEY :
277  grn_dat_close(ctx, (grn_dat *)s->keys);
278  break;
279  }
280  }
282  GRN_FREE(s);
283  } else {
284  ERR(GRN_NO_MEMORY_AVAILABLE, "grn_db alloc failed");
285  }
286  } else {
287  ERR(GRN_INVALID_ARGUMENT, "inappropriate path");
288  }
289  GRN_API_RETURN(NULL);
290 }
291 
292 static grn_id
293 grn_db_curr_id(grn_ctx *ctx, grn_obj *db)
294 {
295  grn_id curr_id = GRN_ID_NIL;
296  grn_db *s = (grn_db *)db;
297  switch (s->keys->header.type) {
298  case GRN_TABLE_PAT_KEY :
299  curr_id = grn_pat_curr_id(ctx, (grn_pat *)s->keys);
300  break;
301  case GRN_TABLE_DAT_KEY :
302  curr_id = grn_dat_curr_id(ctx, (grn_dat *)s->keys);
303  break;
304  }
305  return curr_id;
306 }
307 
308 /* s must be validated by caller */
309 grn_rc
311 {
312  grn_id id;
313  db_value *vp;
314  grn_db *s = (grn_db *)db;
315  grn_bool ctx_used_db;
316  if (!s) { return GRN_INVALID_ARGUMENT; }
318  ctx_used_db = ctx->impl && ctx->impl->db == db;
319  if (ctx_used_db) {
321  if (ctx->impl->parser) {
323  }
324  if (ctx->impl->values) {
325  grn_db_obj *o;
326  GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, {
327  grn_obj_close(ctx, *((grn_obj **)o));
328  });
329  grn_array_truncate(ctx, ctx->impl->values);
330  }
331  }
332  GRN_TINY_ARRAY_EACH(&s->values, 1, grn_db_curr_id(ctx, db), id, vp, {
333  if (vp->ptr) { grn_obj_close(ctx, vp->ptr); }
334  });
335 /* grn_tiny_array_fin should be refined.. */
336 #ifdef WIN32
337  {
338  grn_tiny_array *a = &s->values;
339  CRITICAL_SECTION_FIN(a->lock);
340  }
341 #endif
343  switch (s->keys->header.type) {
344  case GRN_TABLE_PAT_KEY :
345  grn_pat_close(ctx, (grn_pat *)s->keys);
346  break;
347  case GRN_TABLE_DAT_KEY :
348  grn_dat_close(ctx, (grn_dat *)s->keys);
349  break;
350  }
351  CRITICAL_SECTION_FIN(s->lock);
352  if (s->specs) { grn_ja_close(ctx, s->specs); }
353  GRN_FREE(s);
354  if (ctx_used_db) {
355  grn_cache *cache;
356  cache = grn_cache_current_get(ctx);
357  if (cache) {
358  grn_cache_expire(cache, -1);
359  }
360  ctx->impl->db = NULL;
361  }
363 }
364 
365 grn_obj *
366 grn_ctx_get(grn_ctx *ctx, const char *name, int name_size)
367 {
368  grn_id id;
369  grn_obj *obj = NULL;
370  grn_obj *db;
371  if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
372  return NULL;
373  }
375  if (GRN_DB_P(db)) {
376  grn_db *s = (grn_db *)db;
377  if (name_size < 0) {
378  name_size = strlen(name);
379  }
380  if ((id = grn_table_get(ctx, s->keys, name, name_size))) {
381  obj = grn_ctx_at(ctx, id);
382  }
383  }
384  GRN_API_RETURN(obj);
385 }
386 
387 grn_obj *
389 {
390  return (ctx && ctx->impl) ? ctx->impl->db : NULL;
391 }
392 
393 grn_obj *
395 {
396  return (grn_obj *)(((grn_db *)s)->keys);
397 }
398 
399 static grn_io*
400 grn_obj_io(grn_obj *obj)
401 {
402  grn_io *io = NULL;
403  if (obj) {
404  if (obj->header.type == GRN_DB) { obj = ((grn_db *)obj)->keys; }
405  switch (obj->header.type) {
406  case GRN_TABLE_PAT_KEY :
407  io = ((grn_pat *)obj)->io;
408  break;
409  case GRN_TABLE_DAT_KEY :
410  io = ((grn_dat *)obj)->io;
411  break;
412  case GRN_TABLE_HASH_KEY :
413  io = ((grn_hash *)obj)->io;
414  break;
415  case GRN_TABLE_NO_KEY :
416  io = ((grn_array *)obj)->io;
417  break;
418  case GRN_COLUMN_VAR_SIZE :
419  io = ((grn_ja *)obj)->io;
420  break;
421  case GRN_COLUMN_FIX_SIZE :
422  io = ((grn_ra *)obj)->io;
423  break;
424  case GRN_COLUMN_INDEX :
425  io = ((grn_ii *)obj)->seg;
426  break;
427  }
428  }
429  return io;
430 }
431 
432 uint32_t
434 {
435  return grn_obj_io(((grn_db *)s)->keys)->header->lastmod;
436 }
437 
438 void
440 {
441  grn_timeval tv;
442  grn_timeval_now(ctx, &tv);
443  grn_obj_io(s)->header->lastmod = tv.tv_sec;
444 }
445 
446 #define IS_TEMP(obj) (DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)
447 
448 void
450 {
451  grn_timeval tv_;
452  if (!tv) {
453  grn_timeval_now(ctx, &tv_);
454  tv = &tv_;
455  }
456  if (obj) {
457  switch (obj->header.type) {
458  case GRN_DB :
459  grn_obj_io(obj)->header->lastmod = tv->tv_sec;
460  break;
461  case GRN_TABLE_HASH_KEY :
462  case GRN_TABLE_PAT_KEY :
463  case GRN_TABLE_DAT_KEY :
464  case GRN_TABLE_NO_KEY :
465  case GRN_COLUMN_VAR_SIZE :
466  case GRN_COLUMN_FIX_SIZE :
467  case GRN_COLUMN_INDEX :
468  if (!IS_TEMP(obj)) {
469  grn_obj_io(DB_OBJ(obj)->db)->header->lastmod = tv->tv_sec;
470  }
471  break;
472  }
473  }
474 }
475 
476 grn_rc
477 grn_db_check_name(grn_ctx *ctx, const char *name, unsigned int name_size)
478 {
479  int len;
480  const char *name_end = name + name_size;
481  if (name_size > 0 &&
482  *name == GRN_DB_PSEUDO_COLUMN_PREFIX) {
483  return GRN_INVALID_ARGUMENT;
484  }
485  while (name < name_end) {
486  char c = *name;
487  if ((unsigned int)((c | 0x20) - 'a') >= 26u &&
488  (unsigned int)(c - '0') >= 10u &&
489  c != '_' &&
490  c != '-' &&
491  c != '#' &&
492  c != '@') {
493  return GRN_INVALID_ARGUMENT;
494  }
495  if (!(len = grn_charlen(ctx, name, name_end))) { break; }
496  name += len;
497  }
498  return GRN_SUCCESS;
499 }
500 
501 #define GRN_TYPE_SIZE(type) ((type)->range)
502 
503 grn_obj *
504 grn_type_create(grn_ctx *ctx, const char *name, unsigned int name_size,
505  grn_obj_flags flags, unsigned int size)
506 {
507  grn_id id;
508  struct _grn_type *res = NULL;
509  grn_obj *db;
510  if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
511  ERR(GRN_INVALID_ARGUMENT, "db not initialized");
512  return NULL;
513  }
515  if (grn_db_check_name(ctx, name, name_size)) {
516  GRN_DB_CHECK_NAME_ERR("[type][create]", name, name_size);
517  GRN_API_RETURN(NULL);
518  }
519  if (!GRN_DB_P(db)) {
520  ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
521  GRN_API_RETURN(NULL);
522  }
523  id = grn_obj_register(ctx, db, name, name_size);
524  if (id && (res = GRN_MALLOC(sizeof(grn_db_obj)))) {
526  res->obj.header.flags = flags;
527  res->obj.header.domain = GRN_ID_NIL;
528  GRN_TYPE_SIZE(&res->obj) = size;
529  if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
530  // grn_obj_delete(ctx, db, id);
531  GRN_FREE(res);
532  GRN_API_RETURN(NULL);
533  }
534  }
535  GRN_API_RETURN((grn_obj *)res);
536 }
537 
538 static grn_obj *
539 grn_type_open(grn_ctx *ctx, grn_obj_spec *spec)
540 {
541  struct _grn_type *res;
542  res = GRN_MALLOC(sizeof(struct _grn_type));
543  if (res) {
545  res->obj.header = spec->header;
546  GRN_TYPE_SIZE(&res->obj) = GRN_TYPE_SIZE(spec);
547  }
548  return (grn_obj *)res;
549 }
550 
551 grn_obj *
552 grn_proc_create(grn_ctx *ctx, const char *name, int name_size, grn_proc_type type,
554  unsigned int nvars, grn_expr_var *vars)
555 {
556  grn_proc *res = NULL;
557  grn_id id = GRN_ID_NIL;
558  grn_id range = GRN_ID_NIL;
559  int added = 0;
560  grn_obj *db;
561  const char *path = ctx->impl->plugin_path;
562  if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
563  ERR(GRN_INVALID_ARGUMENT, "db not initialized");
564  return NULL;
565  }
567  if (path) {
568  range = grn_plugin_reference(ctx, path);
569  }
570  if (name_size < 0) {
571  name_size = strlen(name);
572  }
573  if (grn_db_check_name(ctx, name, name_size)) {
574  GRN_DB_CHECK_NAME_ERR("[proc][create]", name, name_size);
575  GRN_API_RETURN(NULL);
576  }
577  if (!GRN_DB_P(db)) {
578  ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
579  GRN_API_RETURN(NULL);
580  }
581  if (name && name_size) {
582  grn_db *s = (grn_db *)db;
583  if (!(id = grn_table_get(ctx, s->keys, name, name_size))) {
584  if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
585  ERR(GRN_NO_MEMORY_AVAILABLE, "grn_table_add failed");
586  GRN_API_RETURN(NULL);
587  }
588  }
589  if (!added) {
590  db_value *vp;
591  if ((vp = grn_tiny_array_at(&s->values, id)) && (res = (grn_proc *)vp->ptr)) {
592  if (res->funcs[PROC_INIT] ||
593  res->funcs[PROC_NEXT] ||
594  res->funcs[PROC_FIN]) {
595  ERR(GRN_INVALID_ARGUMENT, "already used name");
596  GRN_API_RETURN(NULL);
597  }
598  } else {
599  added = 1;
600  }
601  }
602  } else if (ctx->impl && ctx->impl->values) {
603  id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
604  added = 1;
605  }
606  if (!res) { res = GRN_MALLOCN(grn_proc, 1); }
607  if (res) {
609  res->obj.db = db;
610  res->obj.id = id;
611  res->obj.header.domain = GRN_ID_NIL;
612  res->obj.header.flags = path ? GRN_OBJ_CUSTOM_NAME : 0;
613  res->obj.range = range;
614  res->type = type;
615  res->funcs[PROC_INIT] = init;
616  res->funcs[PROC_NEXT] = next;
617  res->funcs[PROC_FIN] = fin;
618  res->selector = NULL;
619  GRN_TEXT_INIT(&res->name_buf, 0);
620  res->vars = NULL;
621  res->nvars = 0;
622  if (added) {
623  if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
624  // grn_obj_delete(ctx, db, id);
625  GRN_FREE(res);
626  GRN_API_RETURN(NULL);
627  }
628  }
629  while (nvars--) {
630  grn_obj *v = grn_expr_add_var(ctx, (grn_obj *)res, vars->name, vars->name_size);
631  GRN_OBJ_INIT(v, vars->value.header.type, 0, vars->value.header.domain);
632  GRN_TEXT_PUT(ctx, v, GRN_TEXT_VALUE(&vars->value), GRN_TEXT_LEN(&vars->value));
633  vars++;
634  }
635  }
636  GRN_API_RETURN((grn_obj *)res);
637 }
638 
639 /* grn_table */
640 
641 static void
642 calc_rec_size(grn_obj_flags flags, uint32_t max_n_subrecs, uint32_t range_size,
643  uint8_t *subrec_size, uint8_t *subrec_offset,
644  uint32_t *key_size, uint32_t *value_size)
645 {
646  *subrec_size = 0;
647  *subrec_offset = 0;
648  if (flags & GRN_OBJ_WITH_SUBREC) {
649  switch (flags & GRN_OBJ_UNIT_MASK) {
651  break;
653  *subrec_offset = sizeof(grn_id);
654  *subrec_size = sizeof(uint32_t);
655  break;
657  *subrec_offset = sizeof(grn_id);
658  *subrec_size = sizeof(uint32_t) + sizeof(uint32_t);
659  break;
661  *key_size += sizeof(uint32_t);
662  break;
664  *key_size += sizeof(uint32_t);
665  *subrec_offset = sizeof(grn_id) + sizeof(uint32_t);
666  *subrec_size = sizeof(uint32_t);
667  break;
669  *key_size += sizeof(uint32_t) + sizeof(uint32_t);
670  break;
672  *subrec_size = range_size;
673  break;
675  *subrec_size = range_size + sizeof(uint32_t);
676  break;
678  *subrec_size = range_size + sizeof(uint32_t) + sizeof(uint32_t);
679  break;
680  }
681  *value_size = (uintptr_t)GRN_RSET_SUBRECS_NTH((((grn_rset_recinfo *)0)->subrecs),
682  *subrec_size, max_n_subrecs);
683  } else {
684  *value_size = range_size;
685  }
686 }
687 
688 static void _grn_obj_remove(grn_ctx *ctx, grn_obj *obj);
689 
690 static grn_rc
691 grn_table_create_validate(grn_ctx *ctx, const char *name, unsigned int name_size,
692  const char *path, grn_obj_flags flags,
693  grn_obj *key_type, grn_obj *value_type)
694 {
695  switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
697  if (flags & GRN_OBJ_KEY_WITH_SIS) {
699  "[table][create] "
700  "key with SIS isn't available for hash table: <%.*s>",
701  name_size, name);
702  }
703  break;
704  case GRN_OBJ_TABLE_PAT_KEY :
705  break;
706  case GRN_OBJ_TABLE_DAT_KEY :
707  break;
708  case GRN_OBJ_TABLE_NO_KEY :
709  if (key_type) {
710  int key_name_size;
711  char key_name[GRN_TABLE_MAX_KEY_SIZE];
712  key_name_size = grn_obj_name(ctx, key_type, key_name,
715  "[table][create] "
716  "key isn't available for no key table: <%.*s> (%.*s)",
717  name_size, name, key_name_size, key_name);
718  } else if (flags & GRN_OBJ_KEY_WITH_SIS) {
720  "[table][create] "
721  "key with SIS isn't available for no key table: <%.*s>",
722  name_size, name);
723  } else if (flags & GRN_OBJ_KEY_NORMALIZE) {
725  "[table][create] "
726  "key normalization isn't available for no key table: <%.*s>",
727  name_size, name);
728  }
729  break;
730  }
731  return ctx->rc;
732 }
733 
734 static grn_obj *
735 grn_table_create_with_max_n_subrecs(grn_ctx *ctx, const char *name,
736  unsigned int name_size, const char *path,
737  grn_obj_flags flags, grn_obj *key_type,
738  grn_obj *value_type, uint32_t max_n_subrecs)
739 {
740  grn_id id;
741  grn_id domain = GRN_ID_NIL, range = GRN_ID_NIL;
742  uint32_t key_size, value_size = 0, range_size = 0;
743  uint8_t subrec_size, subrec_offset;
744  grn_obj *res = NULL;
745  grn_obj *db;
746  char buffer[PATH_MAX];
747  if (!ctx->impl || !(db = ctx->impl->db)) {
748  ERR(GRN_INVALID_ARGUMENT, "[table][create] db not initialized");
749  return NULL;
750  }
751  if (grn_db_check_name(ctx, name, name_size)) {
752  GRN_DB_CHECK_NAME_ERR("[table][create]", name, name_size);
753  return NULL;
754  }
755  if (!GRN_DB_P(db)) {
756  ERR(GRN_INVALID_ARGUMENT, "[table][create] invalid db assigned");
757  return NULL;
758  }
759  if (grn_table_create_validate(ctx, name, name_size, path, flags,
760  key_type, value_type)) {
761  return NULL;
762  }
763  if (key_type) {
764  domain = DB_OBJ(key_type)->id;
765  switch (key_type->header.type) {
766  case GRN_TYPE :
767  {
768  grn_db_obj *t = (grn_db_obj *)key_type;
769  flags |= t->header.flags;
770  key_size = GRN_TYPE_SIZE(t);
771  if (key_size > GRN_TABLE_MAX_KEY_SIZE) {
772  int type_name_size;
773  char type_name[GRN_TABLE_MAX_KEY_SIZE];
774  type_name_size = grn_obj_name(ctx, key_type, type_name,
777  "[table][create] key size too big: <%.*s> <%.*s>(%u) (max:%u)",
778  name_size, name,
779  type_name_size, type_name,
780  key_size, GRN_TABLE_MAX_KEY_SIZE);
781  return NULL;
782  }
783  }
784  break;
785  case GRN_TABLE_HASH_KEY :
786  case GRN_TABLE_PAT_KEY :
787  case GRN_TABLE_DAT_KEY :
788  case GRN_TABLE_NO_KEY :
789  key_size = sizeof(grn_id);
790  break;
791  default :
792  {
793  int key_name_size;
794  char key_name[GRN_TABLE_MAX_KEY_SIZE];
795  key_name_size = grn_obj_name(ctx, key_type, key_name,
798  "[table][create] key type must be type or table: <%.*s> (%.*s)",
799  name_size, name, key_name_size, key_name);
800  return NULL;
801  }
802  break;
803  }
804  } else {
805  key_size = (flags & GRN_OBJ_KEY_VAR_SIZE) ? GRN_TABLE_MAX_KEY_SIZE : sizeof(grn_id);
806  }
807  if (value_type) {
808  range = DB_OBJ(value_type)->id;
809  switch (value_type->header.type) {
810  case GRN_TYPE :
811  {
812  grn_db_obj *t = (grn_db_obj *)value_type;
813  if (t->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
814  int type_name_size;
815  char type_name[GRN_TABLE_MAX_KEY_SIZE];
816  type_name_size = grn_obj_name(ctx, value_type, type_name,
819  "[table][create] value type must be fixed size: <%.*s> (%.*s)",
820  name_size, name, type_name_size, type_name);
821  return NULL;
822  }
823  range_size = GRN_TYPE_SIZE(t);
824  }
825  break;
826  case GRN_TABLE_HASH_KEY :
827  case GRN_TABLE_PAT_KEY :
828  case GRN_TABLE_DAT_KEY :
829  case GRN_TABLE_NO_KEY :
830  range_size = sizeof(grn_id);
831  break;
832  default :
833  {
834  int value_name_size;
835  char value_name[GRN_TABLE_MAX_KEY_SIZE];
836  value_name_size = grn_obj_name(ctx, value_type, value_name,
839  "[table][create] value type must be type or table: <%.*s> (%.*s)",
840  name_size, name, value_name_size, value_name);
841  return NULL;
842  }
843  break;
844  }
845  }
846 
847  id = grn_obj_register(ctx, db, name, name_size);
848  if (ERRP(ctx, GRN_ERROR)) { return NULL; }
849  if (GRN_OBJ_PERSISTENT & flags) {
850  GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:table_create %.*s", name_size, name);
851  if (!path) {
852  if (GRN_DB_PERSISTENT_P(db)) {
853  gen_pathname(grn_obj_io(db)->path, buffer, id);
854  path = buffer;
855  } else {
856  ERR(GRN_INVALID_ARGUMENT, "path not assigned for persistent table");
857  return NULL;
858  }
859  } else {
860  flags |= GRN_OBJ_CUSTOM_NAME;
861  }
862  } else {
863  if (path) {
864  ERR(GRN_INVALID_ARGUMENT, "path assigned for temporary table");
865  return NULL;
866  }
867  if (GRN_DB_PERSISTENT_P(db) && name && name_size) {
868  ERR(GRN_INVALID_ARGUMENT, "name assigned for temporary table");
869  return NULL;
870  }
871  }
872  calc_rec_size(flags, max_n_subrecs, range_size, &subrec_size,
873  &subrec_offset, &key_size, &value_size);
874  switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
876  res = (grn_obj *)grn_hash_create(ctx, path, key_size, value_size, flags);
877  break;
878  case GRN_OBJ_TABLE_PAT_KEY :
879  res = (grn_obj *)grn_pat_create(ctx, path, key_size, value_size, flags);
880  break;
881  case GRN_OBJ_TABLE_DAT_KEY :
882  res = (grn_obj *)grn_dat_create(ctx, path, key_size, value_size, flags);
883  break;
884  case GRN_OBJ_TABLE_NO_KEY :
885  domain = range;
886  res = (grn_obj *)grn_array_create(ctx, path, value_size, flags);
887  break;
888  }
889  if (res) {
890  DB_OBJ(res)->header.impl_flags = 0;
891  DB_OBJ(res)->header.domain = domain;
892  DB_OBJ(res)->range = range;
893  DB_OBJ(res)->max_n_subrecs = max_n_subrecs;
894  DB_OBJ(res)->subrec_size = subrec_size;
895  DB_OBJ(res)->subrec_offset = subrec_offset;
896  if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
897  _grn_obj_remove(ctx, res);
898  res = NULL;
899  }
900  } else {
901  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
902  }
903  return res;
904 }
905 
906 grn_obj *
907 grn_table_create(grn_ctx *ctx, const char *name, unsigned int name_size,
908  const char *path, grn_obj_flags flags,
909  grn_obj *key_type, grn_obj *value_type)
910 {
911  grn_obj *res;
913  res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
914  flags, key_type, value_type, 0);
915  GRN_API_RETURN(res);
916 }
917 
918 grn_obj *
919 grn_table_create_for_group(grn_ctx *ctx, const char *name,
920  unsigned int name_size, const char *path,
921  grn_obj *group_key, grn_obj *value_type,
922  unsigned int max_n_subrecs)
923 {
924  grn_obj *res = NULL;
925  grn_obj *key_type;
927  key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, group_key));
928  if (key_type) {
929  res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
931  GRN_OBJ_WITH_SUBREC|
933  key_type, value_type, max_n_subrecs);
934  }
935  GRN_API_RETURN(res);
936 }
937 
938 unsigned int
940  grn_id *subrecbuf, int *scorebuf, int buf_size)
941 {
942  unsigned int count = 0;
944  if (GRN_OBJ_TABLEP(table)) {
945  uint32_t value_size;
946  grn_rset_recinfo *ri;
947  uint32_t subrec_size = DB_OBJ(table)->subrec_size;
948  uint32_t max_n_subrecs = DB_OBJ(table)->max_n_subrecs;
949  if (subrec_size < sizeof(grn_id)) { goto exit; }
950  if (!max_n_subrecs) { goto exit; }
951  ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, table, id, &value_size);
952  if (ri) {
953  byte *psubrec = (byte *)ri->subrecs;
954  uint32_t n_subrecs = (uint32_t)GRN_RSET_N_SUBRECS(ri);
955  uint32_t limit = value_size / (GRN_RSET_SCORE_SIZE + subrec_size);
956  if (limit > buf_size) {
957  limit = buf_size;
958  }
959  if (limit > n_subrecs) {
960  limit = n_subrecs;
961  }
962  if (limit > max_n_subrecs) {
963  limit = max_n_subrecs;
964  }
965  for (; count < limit; count++) {
966  if (scorebuf) {
967  scorebuf[count] = *((int *)psubrec);
968  }
969  psubrec += GRN_RSET_SCORE_SIZE;
970  if (subrecbuf) {
971  subrecbuf[count] = *((grn_id *)psubrec);
972  }
973  psubrec += subrec_size;
974  }
975  }
976  }
977 exit :
978  GRN_API_RETURN(count);
979 }
980 
981 grn_obj *
982 grn_table_open(grn_ctx *ctx, const char *name, unsigned int name_size, const char *path)
983 {
984  grn_obj *db;
985  if (!ctx->impl || !(db = ctx->impl->db)) {
986  ERR(GRN_INVALID_ARGUMENT, "db not initialized");
987  return NULL;
988  }
990  if (!GRN_DB_P(db)) {
991  ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
992  GRN_API_RETURN(NULL);
993  } else {
994  grn_obj *res = grn_ctx_get(ctx, name, name_size);
995  if (res) {
996  const char *path2 = grn_obj_path(ctx, res);
997  if (path && (!path2 || strcmp(path, path2))) {
998  ERR(GRN_INVALID_ARGUMENT, "path unmatch");
999  GRN_API_RETURN(NULL);
1000  }
1001  } else if (path) {
1002  uint32_t type = grn_io_detect_type(ctx, path);
1003  if (!type) { GRN_API_RETURN(NULL); }
1004  switch (type) {
1005  case GRN_TABLE_HASH_KEY :
1006  res = (grn_obj *)grn_hash_open(ctx, path);
1007  break;
1008  case GRN_TABLE_PAT_KEY :
1009  res = (grn_obj *)grn_pat_open(ctx, path);
1010  break;
1011  case GRN_TABLE_DAT_KEY :
1012  res = (grn_obj *)grn_dat_open(ctx, path);
1013  break;
1014  case GRN_TABLE_NO_KEY :
1015  res = (grn_obj *)grn_array_open(ctx, path);
1016  break;
1017  }
1018  if (res) {
1019  grn_id id = grn_obj_register(ctx, db, name, name_size);
1021  res->header.domain = GRN_ID_NIL; /* unknown */
1022  DB_OBJ(res)->range = GRN_ID_NIL; /* unknown */
1023  grn_db_obj_init(ctx, db, id, DB_OBJ(res));
1024  }
1025  } else {
1026  ERR(GRN_INVALID_ARGUMENT, "path is missing");
1027  }
1028  GRN_API_RETURN(res);
1029  }
1030 }
1031 
1032 grn_id
1033 grn_table_lcp_search(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
1034 {
1035  grn_id id = GRN_ID_NIL;
1036  GRN_API_ENTER;
1037  switch (table->header.type) {
1038  case GRN_TABLE_PAT_KEY :
1039  {
1040  grn_pat *pat = (grn_pat *)table;
1041  WITH_NORMALIZE(pat, key, key_size, {
1042  id = grn_pat_lcp_search(ctx, pat, key, key_size);
1043  });
1044  }
1045  break;
1046  case GRN_TABLE_DAT_KEY :
1047  {
1048  grn_dat *dat = (grn_dat *)table;
1049  WITH_NORMALIZE(dat, key, key_size, {
1050  id = grn_dat_lcp_search(ctx, dat, key, key_size);
1051  });
1052  }
1053  break;
1054  case GRN_TABLE_HASH_KEY :
1055  {
1056  grn_hash *hash = (grn_hash *)table;
1057  WITH_NORMALIZE(hash, key, key_size, {
1058  id = grn_hash_get(ctx, hash, key, key_size, NULL);
1059  });
1060  }
1061  break;
1062  }
1063  GRN_API_RETURN(id);
1064 }
1065 
1066 typedef struct {
1068  unsigned int section;
1070 
1071 struct _grn_hook {
1074  uint32_t hld_size;
1075 };
1076 
1077 static grn_obj *
1078 default_set_value_hook(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1079 {
1080  grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
1081  if (!pctx) {
1082  ERR(GRN_INVALID_ARGUMENT, "default_set_value_hook failed");
1083  } else {
1084  grn_obj *flags = grn_ctx_pop(ctx);
1085  grn_obj *newvalue = grn_ctx_pop(ctx);
1086  grn_obj *oldvalue = grn_ctx_pop(ctx);
1087  grn_obj *id = grn_ctx_pop(ctx);
1088  grn_hook *h = pctx->currh;
1089  default_set_value_hook_data *data = (void *)NEXT_ADDR(h);
1090  grn_obj *target = grn_ctx_at(ctx, data->target);
1091  int section = data->section;
1092  if (flags) { /* todo */ }
1093  if (target) {
1094  switch (target->header.type) {
1095  case GRN_COLUMN_INDEX :
1096  grn_ii_column_update(ctx, (grn_ii *)target,
1097  GRN_UINT32_VALUE(id),
1098  section, oldvalue, newvalue, NULL);
1099  }
1100  }
1101  }
1102  return NULL;
1103 }
1104 
1105 grn_id
1106 grn_table_add(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size, int *added)
1107 {
1108  grn_id id = GRN_ID_NIL;
1109  GRN_API_ENTER;
1110  if (table) {
1111  int added_ = 0;
1112  switch (table->header.type) {
1113  case GRN_TABLE_PAT_KEY :
1114  {
1115  grn_pat *pat = (grn_pat *)table;
1116  WITH_NORMALIZE(pat, key, key_size, {
1117  if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
1118  if (grn_io_lock(ctx, pat->io, 10000000)) {
1119  id = GRN_ID_NIL;
1120  } else {
1121  id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
1122  grn_io_unlock(pat->io);
1123  }
1124  } else {
1125  id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
1126  }
1127  });
1128  if (added) { *added = added_; }
1129  }
1130  break;
1131  case GRN_TABLE_DAT_KEY :
1132  {
1133  grn_dat *dat = (grn_dat *)table;
1134  WITH_NORMALIZE(dat, key, key_size, {
1135  if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
1136  if (grn_io_lock(ctx, dat->io, 10000000)) {
1137  id = GRN_ID_NIL;
1138  } else {
1139  id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
1140  grn_io_unlock(dat->io);
1141  }
1142  } else {
1143  id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
1144  }
1145  });
1146  if (added) { *added = added_; }
1147  }
1148  break;
1149  case GRN_TABLE_HASH_KEY :
1150  {
1151  grn_hash *hash = (grn_hash *)table;
1152  WITH_NORMALIZE(hash, key, key_size, {
1153  if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
1154  if (grn_io_lock(ctx, hash->io, 10000000)) {
1155  id = GRN_ID_NIL;
1156  } else {
1157  id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
1158  grn_io_unlock(hash->io);
1159  }
1160  } else {
1161  id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
1162  }
1163  });
1164  if (added) { *added = added_; }
1165  }
1166  break;
1167  case GRN_TABLE_NO_KEY :
1168  {
1169  grn_array *array = (grn_array *)table;
1170  if (array->io && !(array->io->flags & GRN_IO_TEMPORARY)) {
1171  if (grn_io_lock(ctx, array->io, 10000000)) {
1172  id = GRN_ID_NIL;
1173  } else {
1174  id = grn_array_add(ctx, array, NULL);
1175  grn_io_unlock(array->io);
1176  }
1177  } else {
1178  id = grn_array_add(ctx, array, NULL);
1179  }
1180  added_ = id ? 1 : 0;
1181  if (added) { *added = added_; }
1182  }
1183  break;
1184  }
1185  if (added_) {
1186  grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT];
1187  if (hooks) {
1188  // todo : grn_proc_ctx_open()
1189  grn_obj id_, flags_, oldvalue_, value_;
1190  grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
1191  GRN_UINT32_INIT(&id_, 0);
1192  GRN_UINT32_INIT(&flags_, 0);
1193  GRN_TEXT_INIT(&oldvalue_, 0);
1195  GRN_TEXT_SET_REF(&value_, key, key_size);
1196  GRN_UINT32_SET(ctx, &id_, id);
1197  GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
1198  while (hooks) {
1199  grn_ctx_push(ctx, &id_);
1200  grn_ctx_push(ctx, &oldvalue_);
1201  grn_ctx_push(ctx, &value_);
1202  grn_ctx_push(ctx, &flags_);
1203  pctx.caller = NULL;
1204  pctx.currh = hooks;
1205  if (hooks->proc) {
1206  hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
1207  } else {
1208  default_set_value_hook(ctx, 1, &table, &pctx.user_data);
1209  }
1210  if (ctx->rc) { break; }
1211  hooks = hooks->next;
1212  pctx.offset++;
1213  }
1214  }
1215  }
1216  }
1217  GRN_API_RETURN(id);
1218 }
1219 
1220 grn_id
1222 {
1223  grn_id id = GRN_ID_NIL;
1224  if (table->header.domain == key->header.domain) {
1225  id = grn_table_get(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key));
1226  } else {
1227  grn_rc rc;
1228  grn_obj buf;
1229  GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
1230  if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
1231  ERR(rc, "cast failed");
1232  } else {
1233  id = grn_table_get(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1234  }
1235  GRN_OBJ_FIN(ctx, &buf);
1236  }
1237  return id;
1238 }
1239 
1240 grn_id
1241 grn_table_add_by_key(grn_ctx *ctx, grn_obj *table, grn_obj *key, int *added)
1242 {
1243  grn_id id = GRN_ID_NIL;
1244  if (table->header.domain == key->header.domain) {
1245  id = grn_table_add(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key), added);
1246  } else {
1247  grn_rc rc;
1248  grn_obj buf;
1249  GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
1250  if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
1251  ERR(rc, "cast failed");
1252  } else {
1253  id = grn_table_add(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), added);
1254  }
1255  GRN_OBJ_FIN(ctx, &buf);
1256  }
1257  return id;
1258 }
1259 
1260 grn_id
1261 grn_table_get(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
1262 {
1263  grn_id id = GRN_ID_NIL;
1264  GRN_API_ENTER;
1265  if (table) {
1266  if (table->header.type == GRN_DB) {
1267  grn_db *db = (grn_db *)table;
1268  table = db->keys;
1269  }
1270  switch (table->header.type) {
1271  case GRN_TABLE_PAT_KEY :
1272  WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1273  id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, NULL);
1274  });
1275  break;
1276  case GRN_TABLE_DAT_KEY :
1277  WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1278  id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, NULL);
1279  });
1280  break;
1281  case GRN_TABLE_HASH_KEY :
1282  WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1283  id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, NULL);
1284  });
1285  break;
1286  }
1287  }
1288  GRN_API_RETURN(id);
1289 }
1290 
1291 grn_id
1293 {
1294  GRN_API_ENTER;
1295  if (table) {
1296  switch (table->header.type) {
1297  case GRN_DB :
1298  {
1299  grn_db *db = (grn_db *)table;
1300  id = grn_table_at(ctx, db->keys, id);
1301  }
1302  break;
1303  case GRN_TABLE_PAT_KEY :
1304  id = grn_pat_at(ctx, (grn_pat *)table, id);
1305  break;
1306  case GRN_TABLE_DAT_KEY :
1307  id = grn_dat_at(ctx, (grn_dat *)table, id);
1308  break;
1309  case GRN_TABLE_HASH_KEY :
1310  id = grn_hash_at(ctx, (grn_hash *)table, id);
1311  break;
1312  case GRN_TABLE_NO_KEY :
1313  id = grn_array_at(ctx, (grn_array *)table, id);
1314  break;
1315  default :
1316  id = GRN_ID_NIL;
1317  }
1318  }
1319  GRN_API_RETURN(id);
1320 }
1321 
1322 inline static grn_id
1323 grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1324  void **value, int *added)
1325 {
1326  grn_id id = GRN_ID_NIL;
1327  if (!key || !key_size) { return GRN_ID_NIL; }
1328  if (table) {
1329  switch (table->header.type) {
1330  case GRN_TABLE_PAT_KEY :
1331  WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1332  id = grn_pat_add(ctx, (grn_pat *)table, key, key_size, value, added);
1333  });
1334  break;
1335  case GRN_TABLE_DAT_KEY :
1336  WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1337  id = grn_dat_add(ctx, (grn_dat *)table, key, key_size, value, added);
1338  });
1339  break;
1340  case GRN_TABLE_HASH_KEY :
1341  WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1342  id = grn_hash_add(ctx, (grn_hash *)table, key, key_size, value, added);
1343  });
1344  break;
1345  case GRN_TABLE_NO_KEY :
1346  id = grn_array_add(ctx, (grn_array *)table, value);
1347  if (added) { *added = id ? 1 : 0; }
1348  break;
1349  }
1350  }
1351  return id;
1352 }
1353 
1354 grn_id
1355 grn_table_add_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1356  void **value, int *added) {
1357  grn_id id;
1358  GRN_API_ENTER;
1359  id = grn_table_add_v_inline(ctx, table, key, key_size, value, added);
1360  GRN_API_RETURN(id);
1361 }
1362 
1363 grn_id
1364 grn_table_get_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1365  void **value)
1366 {
1367  grn_id id = GRN_ID_NIL;
1368  GRN_API_ENTER;
1369  if (table) {
1370  switch (table->header.type) {
1371  case GRN_TABLE_PAT_KEY :
1372  WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1373  id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, value);
1374  });
1375  break;
1376  case GRN_TABLE_DAT_KEY :
1377  WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1378  id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, value);
1379  });
1380  break;
1381  case GRN_TABLE_HASH_KEY :
1382  WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1383  id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, value);
1384  });
1385  break;
1386  }
1387  }
1388  GRN_API_RETURN(id);
1389 }
1390 
1391 int
1392 grn_table_get_key(grn_ctx *ctx, grn_obj *table, grn_id id, void *keybuf, int buf_size)
1393 {
1394  int r = 0;
1395  GRN_API_ENTER;
1396  if (table) {
1397  switch (table->header.type) {
1398  case GRN_TABLE_HASH_KEY :
1399  r = grn_hash_get_key(ctx, (grn_hash *)table, id, keybuf, buf_size);
1400  break;
1401  case GRN_TABLE_PAT_KEY :
1402  r = grn_pat_get_key(ctx, (grn_pat *)table, id, keybuf, buf_size);
1403  break;
1404  case GRN_TABLE_DAT_KEY :
1405  r = grn_dat_get_key(ctx, (grn_dat *)table, id, keybuf, buf_size);
1406  break;
1407  case GRN_TABLE_NO_KEY :
1408  {
1409  grn_array *a = (grn_array *)table;
1410  if (a->obj.header.domain) {
1411  if (buf_size >= a->value_size) {
1412  r = grn_array_get_value(ctx, a, id, keybuf);
1413  } else {
1414  r = a->value_size;
1415  }
1416  }
1417  }
1418  break;
1419  }
1420  }
1421  GRN_API_RETURN(r);
1422 }
1423 
1424 int
1426 {
1427  int r = 0;
1428  GRN_API_ENTER;
1429  if (table) {
1430  switch (table->header.type) {
1431  case GRN_TABLE_HASH_KEY :
1432  r = grn_hash_get_key2(ctx, (grn_hash *)table, id, bulk);
1433  break;
1434  case GRN_TABLE_PAT_KEY :
1435  r = grn_pat_get_key2(ctx, (grn_pat *)table, id, bulk);
1436  break;
1437  case GRN_TABLE_DAT_KEY :
1438  r = grn_dat_get_key2(ctx, (grn_dat *)table, id, bulk);
1439  break;
1440  case GRN_TABLE_NO_KEY :
1441  {
1442  grn_array *a = (grn_array *)table;
1443  if (a->obj.header.domain) {
1444  if (!grn_bulk_space(ctx, bulk, a->value_size)) {
1445  char *curr = GRN_BULK_CURR(bulk);
1446  r = grn_array_get_value(ctx, a, id, curr - a->value_size);
1447  }
1448  }
1449  }
1450  break;
1451  }
1452  }
1453  GRN_API_RETURN(r);
1454 }
1455 
1456 static grn_rc
1457 grn_obj_clear_value(grn_ctx *ctx, grn_obj *obj, grn_id id)
1458 {
1459  grn_rc rc = GRN_SUCCESS;
1460  if (GRN_DB_OBJP(obj)) {
1461  grn_obj buf;
1462  grn_id range = DB_OBJ(obj)->range;
1463  GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
1464  switch (obj->header.type) {
1465  case GRN_COLUMN_VAR_SIZE :
1466  case GRN_COLUMN_FIX_SIZE :
1467  rc = grn_obj_set_value(ctx, obj, id, &buf, GRN_OBJ_SET);
1468  break;
1469  }
1470  GRN_OBJ_FIN(ctx, &buf);
1471  }
1472  return rc;
1473 }
1474 
1475 static void
1476 call_delete_hook(grn_ctx *ctx, grn_obj *table, grn_id rid, const void *key, unsigned int key_size)
1477 {
1478  if (rid) {
1479  grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_DELETE];
1480  if (hooks) {
1481  // todo : grn_proc_ctx_open()
1482  grn_obj id_, flags_, oldvalue_, value_;
1483  grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
1484  GRN_UINT32_INIT(&id_, 0);
1485  GRN_UINT32_INIT(&flags_, 0);
1487  GRN_TEXT_INIT(&value_, 0);
1488  GRN_TEXT_SET_REF(&oldvalue_, key, key_size);
1489  GRN_UINT32_SET(ctx, &id_, rid);
1490  GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
1491  grn_ctx_push(ctx, &id_);
1492  grn_ctx_push(ctx, &oldvalue_);
1493  grn_ctx_push(ctx, &value_);
1494  grn_ctx_push(ctx, &flags_);
1495  while (hooks) {
1496  pctx.caller = NULL;
1497  pctx.currh = hooks;
1498  if (hooks->proc) {
1499  hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
1500  } else {
1501  default_set_value_hook(ctx, 1, &table, &pctx.user_data);
1502  }
1503  if (ctx->rc) { break; }
1504  hooks = hooks->next;
1505  pctx.offset++;
1506  }
1507  }
1508  }
1509 }
1510 
1511 static void
1512 clear_column_values(grn_ctx *ctx, grn_obj *table, grn_id rid)
1513 {
1514  if (rid) {
1515  grn_hash *cols;
1516  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1518  if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
1519  grn_id *key;
1520  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
1521  grn_obj *col = grn_ctx_at(ctx, *key);
1522  if (col) { grn_obj_clear_value(ctx, col, rid); }
1523  });
1524  }
1525  grn_hash_close(ctx, cols);
1526  }
1527  }
1528 }
1529 
1530 static void
1531 delete_reference_records_in_index(grn_ctx *ctx, grn_obj *table, grn_id id,
1532  grn_obj *index)
1533 {
1534  grn_ii *ii = (grn_ii *)index;
1535  grn_ii_cursor *ii_cursor = NULL;
1536  grn_ii_posting *posting;
1537  grn_obj source_ids;
1538  unsigned int i, n_ids;
1539  grn_obj sources;
1540 
1541  GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
1542  GRN_PTR_INIT(&sources, GRN_OBJ_VECTOR, 0);
1543 
1544  grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
1545  n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
1546  if (n_ids == 0) {
1547  goto exit;
1548  }
1549 
1550  for (i = 0; i < n_ids; i++) {
1551  grn_id source_id;
1552  grn_obj *source;
1553 
1554  source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
1555  source = grn_ctx_at(ctx, source_id);
1556  GRN_PTR_PUT(ctx, &sources, source);
1557  }
1558 
1559  ii_cursor = grn_ii_cursor_open(ctx, ii, id, GRN_ID_NIL, GRN_ID_MAX,
1560  ii->n_elements, 0);
1561  if (!ii_cursor) {
1562  goto exit;
1563  }
1564 
1565  while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
1566  grn_obj *source = GRN_PTR_VALUE_AT(&sources, posting->sid - 1);
1567  switch (source->header.type) {
1568  case GRN_COLUMN_VAR_SIZE :
1569  switch (source->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
1570  case GRN_OBJ_COLUMN_SCALAR :
1571  grn_obj_clear_value(ctx, source, posting->rid);
1572  break;
1573  case GRN_OBJ_COLUMN_VECTOR :
1574  {
1575  grn_obj value;
1576  grn_obj new_value;
1577  GRN_TEXT_INIT(&value, 0);
1578  grn_obj_get_value(ctx, source, posting->rid, &value);
1579  if (value.header.type == GRN_UVECTOR) {
1580  int i, n_ids;
1581  GRN_RECORD_INIT(&new_value, GRN_OBJ_VECTOR, value.header.domain);
1582  n_ids = GRN_BULK_VSIZE(&value) / sizeof(grn_id);
1583  for (i = 0; i < n_ids; i++) {
1584  grn_id reference_id = GRN_RECORD_VALUE_AT(&value, i);
1585  if (reference_id == id) {
1586  continue;
1587  }
1588  GRN_RECORD_PUT(ctx, &new_value, reference_id);
1589  }
1590  } else {
1591  unsigned int i, n_elements;
1592  GRN_TEXT_INIT(&new_value, GRN_OBJ_VECTOR);
1593  n_elements = grn_vector_size(ctx, &value);
1594  for (i = 0; i < n_elements; i++) {
1595  const char *content;
1596  unsigned int content_length;
1597  unsigned int weight;
1598  grn_id domain;
1599  content_length =
1600  grn_vector_get_element(ctx, &value, i,
1601  &content, &weight, &domain);
1602  if (grn_table_get(ctx, table, content, content_length) == id) {
1603  continue;
1604  }
1605  grn_vector_add_element(ctx, &new_value, content, content_length,
1606  weight, domain);
1607  }
1608  }
1609  grn_obj_set_value(ctx, source, posting->rid, &new_value,
1610  GRN_OBJ_SET);
1611  GRN_OBJ_FIN(ctx, &new_value);
1612  GRN_OBJ_FIN(ctx, &value);
1613  }
1614  break;
1615  }
1616  break;
1617  case GRN_COLUMN_FIX_SIZE :
1618  grn_obj_clear_value(ctx, source, posting->rid);
1619  break;
1620  }
1621  }
1622 
1623 exit:
1624  if (ii_cursor) {
1625  grn_ii_cursor_close(ctx, ii_cursor);
1626  }
1627  grn_obj_unlink(ctx, &source_ids);
1628  {
1629  int i, n_sources;
1630  n_sources = GRN_BULK_VSIZE(&sources) / sizeof(grn_obj *);
1631  for (i = 0; i < n_sources; i++) {
1632  grn_obj *source = GRN_PTR_VALUE_AT(&sources, i);
1633  grn_obj_unlink(ctx, source);
1634  }
1635  grn_obj_unlink(ctx, &sources);
1636  }
1637 }
1638 
1639 static grn_rc
1640 delete_reference_records(grn_ctx *ctx, grn_obj *table, grn_id id)
1641 {
1642  grn_hash *cols;
1643  grn_id *key;
1644 
1645  cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1647  if (!cols) {
1648  return ctx->rc;
1649  }
1650 
1651  if (!grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
1652  grn_hash_close(ctx, cols);
1653  return ctx->rc;
1654  }
1655 
1656  GRN_HASH_EACH(ctx, cols, tid, &key, NULL, NULL, {
1657  grn_obj *col = grn_ctx_at(ctx, *key);
1658  if (col && col->header.type == GRN_COLUMN_INDEX) {
1659  delete_reference_records_in_index(ctx, table, id, col);
1660  if (ctx->rc != GRN_SUCCESS) {
1661  break;
1662  }
1663  }
1664  });
1665 
1666  grn_hash_close(ctx, cols);
1667 
1668  return ctx->rc;
1669 }
1670 
1671 grn_rc
1672 grn_table_delete(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
1673 {
1674  grn_id rid = GRN_ID_NIL;
1676  GRN_API_ENTER;
1677  if (table) {
1678  if (key && key_size) { rid = grn_table_get(ctx, table, key, key_size); }
1679  if (rid) {
1680  rc = delete_reference_records(ctx, table, rid);
1681  if (rc != GRN_SUCCESS) {
1682  goto exit;
1683  }
1684  call_delete_hook(ctx, table, rid, key, key_size);
1685  clear_column_values(ctx, table, rid);
1686  switch (table->header.type) {
1687  case GRN_DB :
1688  /* todo : delete tables and columns from db */
1689  break;
1690  case GRN_TABLE_PAT_KEY :
1691  WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1692  grn_pat *pat = (grn_pat *)table;
1693  if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
1694  if (!(rc = grn_io_lock(ctx, pat->io, 10000000))) {
1695  rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
1696  grn_io_unlock(pat->io);
1697  }
1698  } else {
1699  rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
1700  }
1701  });
1702  break;
1703  case GRN_TABLE_DAT_KEY :
1704  WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1705  grn_dat *dat = (grn_dat *)table;
1706  if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
1707  if (!(rc = grn_io_lock(ctx, dat->io, 10000000))) {
1708  rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
1709  grn_io_unlock(dat->io);
1710  }
1711  } else {
1712  rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
1713  }
1714  });
1715  break;
1716  case GRN_TABLE_HASH_KEY :
1717  WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1718  grn_hash *hash = (grn_hash *)table;
1719  if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
1720  if (!(rc = grn_io_lock(ctx, hash->io, 10000000))) {
1721  rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
1722  grn_io_unlock(hash->io);
1723  }
1724  } else {
1725  rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
1726  }
1727  });
1728  break;
1729  }
1730  grn_obj_touch(ctx, table, NULL);
1731  }
1732  }
1733 exit:
1734  GRN_API_RETURN(rc);
1735 }
1736 
1737 grn_rc
1739  grn_table_delete_optarg *optarg)
1740 {
1742  if (table) {
1743  const void *key;
1744  unsigned int key_size;
1745  if (id) {
1746  rc = delete_reference_records(ctx, table, id);
1747  if (rc != GRN_SUCCESS) {
1748  goto exit;
1749  }
1750  if ((key = _grn_table_key(ctx, table, id, &key_size))) {
1751  call_delete_hook(ctx, table, id, key, key_size);
1752  }
1753  // todo : support optarg
1754  switch (table->header.type) {
1755  case GRN_TABLE_PAT_KEY :
1756  rc = grn_pat_delete_by_id(ctx, (grn_pat *)table, id, optarg);
1757  break;
1758  case GRN_TABLE_DAT_KEY :
1759  rc = grn_dat_delete_by_id(ctx, (grn_dat *)table, id, optarg);
1760  break;
1761  case GRN_TABLE_HASH_KEY :
1762  rc = grn_hash_delete_by_id(ctx, (grn_hash *)table, id, optarg);
1763  break;
1764  case GRN_TABLE_NO_KEY :
1765  rc = grn_array_delete_by_id(ctx, (grn_array *)table, id, optarg);
1766  break;
1767  }
1768  if (rc == GRN_SUCCESS) {
1769  clear_column_values(ctx, table, id);
1770  }
1771  }
1772  }
1773 exit:
1774  return rc;
1775 }
1776 
1777 grn_rc
1779 {
1780  grn_rc rc;
1781  grn_io *io;
1782  GRN_API_ENTER;
1783  if ((io = grn_obj_io(table)) && !(io->flags & GRN_IO_TEMPORARY)) {
1784  if (!(rc = grn_io_lock(ctx, io, 10000000))) {
1785  rc = _grn_table_delete_by_id(ctx, table, id, NULL);
1786  grn_io_unlock(io);
1787  }
1788  } else {
1789  rc = _grn_table_delete_by_id(ctx, table, id, NULL);
1790  }
1791  grn_obj_touch(ctx, table, NULL);
1792  GRN_API_RETURN(rc);
1793 }
1794 
1798 
1799 grn_rc
1801 {
1803  GRN_API_ENTER;
1804  if (column) {
1805  grn_hook *hooks;
1806  switch (column->header.type) {
1807  case GRN_COLUMN_INDEX :
1808  rc = grn_ii_truncate(ctx, (grn_ii *)column);
1809  break;
1810  case GRN_COLUMN_VAR_SIZE :
1811  for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
1812  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
1813  grn_obj *target = grn_ctx_at(ctx, data->target);
1814  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
1815  if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
1816  }
1817  rc = grn_ja_truncate(ctx, (grn_ja *)column);
1818  break;
1819  case GRN_COLUMN_FIX_SIZE :
1820  for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
1821  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
1822  grn_obj *target = grn_ctx_at(ctx, data->target);
1823  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
1824  if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
1825  }
1826  rc = grn_ra_truncate(ctx, (grn_ra *)column);
1827  break;
1828  }
1829  }
1830 exit :
1831  GRN_API_RETURN(rc);
1832 }
1833 
1834 grn_rc
1836 {
1838  GRN_API_ENTER;
1839  if (table) {
1840  grn_hook *hooks;
1841  grn_hash *cols;
1842  grn_obj *tokenizer;
1843  grn_obj *normalizer;
1844  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1846  if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
1847  grn_id *key;
1848  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
1849  grn_obj *col = grn_ctx_at(ctx, *key);
1850  if (col) { grn_column_truncate(ctx, col); }
1851  });
1852  }
1853  grn_hash_close(ctx, cols);
1854  }
1855  grn_table_get_info(ctx, table, NULL, NULL, &tokenizer, &normalizer);
1856  switch (table->header.type) {
1857  case GRN_TABLE_PAT_KEY :
1858  for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
1859  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
1860  grn_obj *target = grn_ctx_at(ctx, data->target);
1861  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
1862  if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
1863  }
1864  rc = grn_pat_truncate(ctx, (grn_pat *)table);
1865  break;
1866  case GRN_TABLE_DAT_KEY :
1867  for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
1868  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
1869  grn_obj *target = grn_ctx_at(ctx, data->target);
1870  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
1871  if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
1872  }
1873  rc = grn_dat_truncate(ctx, (grn_dat *)table);
1874  break;
1875  case GRN_TABLE_HASH_KEY :
1876  for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
1877  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
1878  grn_obj *target = grn_ctx_at(ctx, data->target);
1879  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
1880  if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
1881  }
1882  rc = grn_hash_truncate(ctx, (grn_hash *)table);
1883  break;
1884  case GRN_TABLE_NO_KEY :
1885  rc = grn_array_truncate(ctx, (grn_array *)table);
1886  break;
1887  }
1888  grn_obj_set_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
1889  grn_obj_set_info(ctx, table, GRN_INFO_NORMALIZER, normalizer);
1890  grn_obj_touch(ctx, table, NULL);
1891  }
1892 exit :
1893  GRN_API_RETURN(rc);
1894 }
1895 
1896 grn_rc
1898  grn_encoding *encoding, grn_obj **tokenizer,
1899  grn_obj **normalizer)
1900 {
1902  GRN_API_ENTER;
1903  if (table) {
1904  switch (table->header.type) {
1905  case GRN_TABLE_PAT_KEY :
1906  if (flags) { *flags = ((grn_pat *)table)->obj.header.flags; }
1907  if (encoding) { *encoding = ((grn_pat *)table)->encoding; }
1908  if (tokenizer) { *tokenizer = ((grn_pat *)table)->tokenizer; }
1909  if (normalizer) { *normalizer = ((grn_pat *)table)->normalizer; }
1910  rc = GRN_SUCCESS;
1911  break;
1912  case GRN_TABLE_DAT_KEY :
1913  if (flags) { *flags = ((grn_dat *)table)->obj.header.flags; }
1914  if (encoding) { *encoding = ((grn_dat *)table)->encoding; }
1915  if (tokenizer) { *tokenizer = ((grn_dat *)table)->tokenizer; }
1916  if (normalizer) { *normalizer = ((grn_dat *)table)->normalizer; }
1917  rc = GRN_SUCCESS;
1918  break;
1919  case GRN_TABLE_HASH_KEY :
1920  if (flags) { *flags = ((grn_hash *)table)->obj.header.flags; }
1921  if (encoding) { *encoding = ((grn_hash *)table)->encoding; }
1922  if (tokenizer) { *tokenizer = ((grn_hash *)table)->tokenizer; }
1923  if (normalizer) { *normalizer = ((grn_hash *)table)->normalizer; }
1924  rc = GRN_SUCCESS;
1925  break;
1926  case GRN_TABLE_NO_KEY :
1927  if (flags) { *flags = 0; }
1928  if (encoding) { *encoding = GRN_ENC_NONE; }
1929  if (tokenizer) { *tokenizer = grn_token_uvector; }
1930  if (normalizer) { *normalizer = NULL; }
1931  rc = GRN_SUCCESS;
1932  break;
1933  }
1934  }
1935  GRN_API_RETURN(rc);
1936 }
1937 
1938 unsigned int
1940 {
1941  unsigned int n = 0;
1942  GRN_API_ENTER;
1943  if (table) {
1944  switch (table->header.type) {
1945  case GRN_DB :
1946  n = grn_table_size(ctx, ((grn_db *)table)->keys);
1947  break;
1948  case GRN_TABLE_PAT_KEY :
1949  n = grn_pat_size(ctx, (grn_pat *)table);
1950  break;
1951  case GRN_TABLE_DAT_KEY :
1952  n = grn_dat_size(ctx, (grn_dat *)table);
1953  break;
1954  case GRN_TABLE_HASH_KEY :
1955  n = GRN_HASH_SIZE((grn_hash *)table);
1956  break;
1957  case GRN_TABLE_NO_KEY :
1958  n = GRN_ARRAY_SIZE((grn_array *)table);
1959  break;
1960  default :
1961  ERR(GRN_INVALID_ARGUMENT, "not supported");
1962  break;
1963  }
1964  } else {
1965  ERR(GRN_INVALID_ARGUMENT, "invalid table assigned");
1966  }
1967  GRN_API_RETURN(n);
1968 }
1969 
1970 inline static void
1971 subrecs_push(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
1972 {
1973  byte *v;
1974  int *c2;
1975  int n = n_subrecs - 1, n2;
1976  while (n) {
1977  n2 = (n - 1) >> 1;
1978  c2 = GRN_RSET_SUBRECS_NTH(subrecs,size,n2);
1979  if (GRN_RSET_SUBRECS_CMP(score, *c2, dir) >= 0) { break; }
1980  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
1981  n = n2;
1982  }
1983  v = subrecs + n * (size + GRN_RSET_SCORE_SIZE);
1984  *((int *)v) = score;
1985  memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
1986 }
1987 
1988 inline static void
1989 subrecs_replace_min(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
1990 {
1991  byte *v;
1992  int n = 0, n1, n2, *c1, *c2;
1993  for (;;) {
1994  n1 = n * 2 + 1;
1995  n2 = n1 + 1;
1996  c1 = n1 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n1) : NULL;
1997  c2 = n2 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n2) : NULL;
1998  if (c1 && GRN_RSET_SUBRECS_CMP(score, *c1, dir) > 0) {
1999  if (c2 &&
2000  GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0 &&
2001  GRN_RSET_SUBRECS_CMP(*c1, *c2, dir) > 0) {
2002  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2003  n = n2;
2004  } else {
2005  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c1);
2006  n = n1;
2007  }
2008  } else {
2009  if (c2 && GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) {
2010  GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2011  n = n2;
2012  } else {
2013  break;
2014  }
2015  }
2016  }
2017  v = subrecs + n * (size + GRN_RSET_SCORE_SIZE);
2018  memcpy(v, &score, GRN_RSET_SCORE_SIZE);
2019  memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
2020 }
2021 
2022 inline static void
2023 grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, int score,
2024  grn_rset_posinfo *pi, int dir)
2025 {
2026  if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
2027  int limit = DB_OBJ(table)->max_n_subrecs;
2028  ri->score += score;
2029  ri->n_subrecs += 1;
2030  if (limit) {
2031  int subrec_size = DB_OBJ(table)->subrec_size;
2032  int n_subrecs = GRN_RSET_N_SUBRECS(ri);
2033  if (pi) {
2034  byte *body = (byte *)pi + DB_OBJ(table)->subrec_offset;
2035  if (limit < n_subrecs) {
2036  if (GRN_RSET_SUBRECS_CMP(score, *ri->subrecs, dir) > 0) {
2037  subrecs_replace_min((byte *)ri->subrecs, subrec_size, limit, score, body, dir);
2038  }
2039  } else {
2040  subrecs_push((byte *)ri->subrecs, subrec_size, n_subrecs, score, body, dir);
2041  }
2042  }
2043  }
2044  }
2045 }
2046 
2047 void
2049  grn_rset_posinfo *pi, int dir)
2050 {
2051  grn_table_add_subrec_inline(table, ri, score, pi, dir);
2052 }
2053 
2056  const void *min, unsigned int min_size,
2057  const void *max, unsigned int max_size,
2058  int offset, int limit, int flags)
2059 {
2060  grn_rc rc;
2061  grn_table_cursor *tc = NULL;
2062  unsigned int table_size;
2063  if (!table) { return tc; }
2064  GRN_API_ENTER;
2065  table_size = grn_table_size(ctx, table);
2066  if (flags & GRN_CURSOR_PREFIX) {
2067  if (offset < 0) {
2069  "can't use negative offset with GRN_CURSOR_PREFIX: %d", offset);
2070  } else if (offset != 0 && offset >= table_size) {
2072  "offset is rather than table size: offset:%d, table_size:%d",
2073  offset, table_size);
2074  } else {
2075  if (limit < -1) {
2077  "can't use small limit rather than -1 with GRN_CURSOR_PREFIX: %d",
2078  limit);
2079  } else if (limit == -1) {
2080  limit = table_size;
2081  }
2082  }
2083  } else {
2084  rc = grn_normalize_offset_and_limit(ctx, table_size, &offset, &limit);
2085  if (rc) {
2086  ERR(rc, "grn_normalize_offset_and_limit failed");
2087  }
2088  }
2089  if (!ctx->rc) {
2090  if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
2091  switch (table->header.type) {
2092  case GRN_TABLE_PAT_KEY :
2093  {
2094  grn_pat *pat = (grn_pat *)table;
2095  WITH_NORMALIZE(pat, min, min_size, {
2096  WITH_NORMALIZE(pat, max, max_size, {
2097  grn_pat_cursor *pat_cursor;
2098  pat_cursor = grn_pat_cursor_open(ctx, pat,
2099  min, min_size,
2100  max, max_size,
2101  offset, limit, flags);
2102  tc = (grn_table_cursor *)pat_cursor;
2103  });
2104  });
2105  }
2106  break;
2107  case GRN_TABLE_DAT_KEY :
2108  {
2109  grn_dat *dat = (grn_dat *)table;
2110  WITH_NORMALIZE(dat, min, min_size, {
2111  WITH_NORMALIZE(dat, max, max_size, {
2112  grn_dat_cursor *dat_cursor;
2113  dat_cursor = grn_dat_cursor_open(ctx, dat,
2114  min, min_size,
2115  max, max_size,
2116  offset, limit, flags);
2117  tc = (grn_table_cursor *)dat_cursor;
2118  });
2119  });
2120  }
2121  break;
2122  case GRN_TABLE_HASH_KEY :
2123  {
2124  grn_hash *hash = (grn_hash *)table;
2125  WITH_NORMALIZE(hash, min, min_size, {
2126  WITH_NORMALIZE(hash, max, max_size, {
2127  grn_hash_cursor *hash_cursor;
2128  hash_cursor = grn_hash_cursor_open(ctx, hash,
2129  min, min_size,
2130  max, max_size,
2131  offset, limit, flags);
2132  tc = (grn_table_cursor *)hash_cursor;
2133  });
2134  });
2135  }
2136  break;
2137  case GRN_TABLE_NO_KEY :
2138  tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
2140  offset, limit, flags);
2141  break;
2142  }
2143  }
2144  if (tc) {
2145  grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
2146  DB_OBJ(tc)->header.domain = GRN_ID_NIL;
2147  DB_OBJ(tc)->range = GRN_ID_NIL;
2148  grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(tc));
2149  }
2150  GRN_API_RETURN(tc);
2151 }
2152 
2155  grn_id min, grn_id max, int flags)
2156 {
2157  grn_table_cursor *tc = NULL;
2158  GRN_API_ENTER;
2159  if (table) {
2160  switch (table->header.type) {
2161  case GRN_TABLE_PAT_KEY :
2162  tc = (grn_table_cursor *)grn_pat_cursor_open(ctx, (grn_pat *)table,
2163  NULL, 0, NULL, 0, 0, -1, flags);
2164  break;
2165  case GRN_TABLE_DAT_KEY :
2166  tc = (grn_table_cursor *)grn_dat_cursor_open(ctx, (grn_dat *)table,
2167  NULL, 0, NULL, 0, 0, -1, flags);
2168  break;
2169  case GRN_TABLE_HASH_KEY :
2170  tc = (grn_table_cursor *)grn_hash_cursor_open(ctx, (grn_hash *)table,
2171  NULL, 0, NULL, 0, 0, -1, flags);
2172  break;
2173  case GRN_TABLE_NO_KEY :
2174  tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
2175  min, max, 0, -1, flags);
2176  break;
2177  }
2178  }
2179  GRN_API_RETURN(tc);
2180 }
2181 
2182 grn_rc
2184 {
2185  grn_rc rc = GRN_SUCCESS;
2186  GRN_API_ENTER;
2187  if (!tc) {
2188  ERR(GRN_INVALID_ARGUMENT, "tc is null");
2189  rc = GRN_INVALID_ARGUMENT;
2190  } else {
2191  {
2192  if (DB_OBJ(tc)->finalizer) {
2193  DB_OBJ(tc)->finalizer(ctx, 1, (grn_obj **)&tc, &DB_OBJ(tc)->user_data);
2194  }
2195  if (DB_OBJ(tc)->source) {
2196  GRN_FREE(DB_OBJ(tc)->source);
2197  }
2198  /*
2199  grn_hook_entry entry;
2200  for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
2201  grn_hook_free(ctx, DB_OBJ(tc)->hooks[entry]);
2202  }
2203  */
2204  grn_obj_delete_by_id(ctx, DB_OBJ(tc)->db, DB_OBJ(tc)->id, GRN_FALSE);
2205  }
2206  switch (tc->header.type) {
2209  break;
2212  break;
2215  break;
2218  break;
2219  default :
2220  rc = GRN_INVALID_ARGUMENT;
2221  break;
2222  }
2223  }
2224  GRN_API_RETURN(rc);
2225 }
2226 
2227 inline static grn_id
2228 grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc)
2229 {
2230  grn_id id = GRN_ID_NIL;
2231  if (!tc) {
2232  ERR(GRN_INVALID_ARGUMENT, "tc is null");
2233  } else {
2234  switch (tc->header.type) {
2236  id = grn_pat_cursor_next(ctx, (grn_pat_cursor *)tc);
2237  break;
2239  id = grn_dat_cursor_next(ctx, (grn_dat_cursor *)tc);
2240  break;
2242  id = grn_hash_cursor_next(ctx, (grn_hash_cursor *)tc);
2243  break;
2245  id = grn_array_cursor_next(ctx, (grn_array_cursor *)tc);
2246  break;
2248  {
2249  grn_posting *ip = grn_index_cursor_next(ctx, (grn_obj *)tc, NULL);
2250  if (ip) { id = ip->rid; }
2251  }
2252  break;
2253  }
2254  }
2255  return id;
2256 }
2257 
2258 grn_id
2260 {
2261  grn_id id;
2262  GRN_API_ENTER;
2263  id = grn_table_cursor_next_inline(ctx, tc);
2264  GRN_API_RETURN(id);
2265 }
2266 
2267 int
2269 {
2270  int len = 0;
2271  GRN_API_ENTER;
2272  if (!tc) {
2273  ERR(GRN_INVALID_ARGUMENT, "tc is null");
2274  } else {
2275  switch (tc->header.type) {
2277  len = grn_pat_cursor_get_key(ctx, (grn_pat_cursor *)tc, key);
2278  break;
2280  len = grn_dat_cursor_get_key(ctx, (grn_dat_cursor *)tc, (const void **)key);
2281  break;
2283  len = grn_hash_cursor_get_key(ctx, (grn_hash_cursor *)tc, key);
2284  break;
2285  default :
2286  ERR(GRN_INVALID_ARGUMENT, "invalid type %d", tc->header.type);
2287  break;
2288  }
2289  }
2290  GRN_API_RETURN(len);
2291 }
2292 
2293 inline static int
2294 grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value)
2295 {
2296  int len = 0;
2297  if (!tc) {
2298  ERR(GRN_INVALID_ARGUMENT, "tc is null");
2299  } else {
2300  switch (tc->header.type) {
2302  len = grn_pat_cursor_get_value(ctx, (grn_pat_cursor *)tc, value);
2303  break;
2305  *value = NULL;
2306  len = 0;
2307  break;
2309  len = grn_hash_cursor_get_value(ctx, (grn_hash_cursor *)tc, value);
2310  break;
2312  len = grn_array_cursor_get_value(ctx, (grn_array_cursor *)tc, value);
2313  break;
2314  default :
2315  ERR(GRN_INVALID_ARGUMENT, "invalid type %d", tc->header.type);
2316  break;
2317  }
2318  }
2319  return len;
2320 }
2321 
2322 int
2324 {
2325  int len;
2326  GRN_API_ENTER;
2327  len = grn_table_cursor_get_value_inline(ctx, tc, value);
2328  GRN_API_RETURN(len);
2329 }
2330 
2331 grn_rc
2333  const void *value, int flags)
2334 {
2336  GRN_API_ENTER;
2337  if (!tc) {
2338  ERR(GRN_INVALID_ARGUMENT, "tc is null");
2339  } else {
2340  switch (tc->header.type) {
2342  rc = grn_pat_cursor_set_value(ctx, (grn_pat_cursor *)tc, value, flags);
2343  break;
2346  break;
2348  rc = grn_hash_cursor_set_value(ctx, (grn_hash_cursor *)tc, value, flags);
2349  break;
2351  rc = grn_array_cursor_set_value(ctx, (grn_array_cursor *)tc, value, flags);
2352  break;
2353  default :
2354  ERR(GRN_INVALID_ARGUMENT, "invalid type %d", tc->header.type);
2355  break;
2356  }
2357  }
2358  GRN_API_RETURN(rc);
2359 }
2360 
2361 grn_rc
2363 {
2365  GRN_API_ENTER;
2366  if (!tc) {
2367  ERR(GRN_INVALID_ARGUMENT, "tc is null");
2368  } else {
2369  switch (tc->header.type) {
2371  rc = grn_pat_cursor_delete(ctx, (grn_pat_cursor *)tc, NULL);
2372  break;
2375  break;
2377  rc = grn_hash_cursor_delete(ctx, (grn_hash_cursor *)tc, NULL);
2378  break;
2380  rc = grn_array_cursor_delete(ctx, (grn_array_cursor *)tc, NULL);
2381  break;
2382  default :
2383  ERR(GRN_INVALID_ARGUMENT, "invalid type %d", tc->header.type);
2384  break;
2385  }
2386  }
2387  GRN_API_RETURN(rc);
2388 }
2389 
2390 grn_obj *
2392 {
2393  grn_obj *obj = NULL;
2394  GRN_API_ENTER;
2395  if (!tc) {
2396  ERR(GRN_INVALID_ARGUMENT, "tc is null");
2397  } else {
2398  switch (tc->header.type) {
2400  obj = (grn_obj *)(((grn_pat_cursor *)tc)->pat);
2401  break;
2403  obj = (grn_obj *)(((grn_dat_cursor *)tc)->dat);
2404  break;
2406  obj = (grn_obj *)(((grn_hash_cursor *)tc)->hash);
2407  break;
2409  obj = (grn_obj *)(((grn_array_cursor *)tc)->array);
2410  break;
2411  default :
2412  ERR(GRN_INVALID_ARGUMENT, "invalid type %d", tc->header.type);
2413  break;
2414  }
2415  }
2416  GRN_API_RETURN(obj);
2417 }
2418 
2419 typedef struct {
2427  int flags;
2429 
2430 grn_obj *
2432  grn_obj *index, grn_id rid_min, grn_id rid_max, int flags)
2433 {
2434  grn_index_cursor *ic = NULL;
2435  GRN_API_ENTER;
2436  if (tc && (ic = GRN_MALLOCN(grn_index_cursor, 1))) {
2437  ic->tc = tc;
2438  ic->index = index;
2439  ic->iic = NULL;
2440  ic->tid = GRN_ID_NIL;
2441  ic->rid_min = rid_min;
2442  ic->rid_max = rid_max;
2443  ic->flags = flags;
2445  {
2446  grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
2447  DB_OBJ(ic)->header.domain = GRN_ID_NIL;
2448  DB_OBJ(ic)->range = GRN_ID_NIL;
2449  grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(ic));
2450  }
2451  }
2452  GRN_API_RETURN((grn_obj *)ic);
2453 }
2454 
2455 grn_posting *
2457 {
2458  grn_ii_posting *ip = NULL;
2460  GRN_API_ENTER;
2461  if (ic->iic) {
2462  if (ic->flags & GRN_OBJ_WITH_POSITION) {
2463  ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2464  while (!ip && grn_ii_cursor_next(ctx, ic->iic)) {
2465  ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2466  break;
2467  }
2468  } else {
2469  ip = grn_ii_cursor_next(ctx, ic->iic);
2470  }
2471  }
2472  if (!ip) {
2473  while ((ic->tid = grn_table_cursor_next_inline(ctx, ic->tc))) {
2474  grn_ii *ii = (grn_ii *)ic->index;
2475  if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
2476  if ((ic->iic = grn_ii_cursor_open(ctx, ii, ic->tid,
2477  ic->rid_min, ic->rid_max,
2478  ii->n_elements, ic->flags))) {
2479  ip = grn_ii_cursor_next(ctx, ic->iic);
2480  if (ip && ic->flags & GRN_OBJ_WITH_POSITION) {
2481  ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2482  }
2483  if (ip) {
2484  break;
2485  }
2486  }
2487  }
2488  }
2489  if (tid) { *tid = ic->tid; }
2490  GRN_API_RETURN((grn_posting *)ip);
2491 }
2492 
2493 grn_rc
2494 grn_table_search(grn_ctx *ctx, grn_obj *table, const void *key, uint32_t key_size,
2495  grn_operator mode, grn_obj *res, grn_operator op)
2496 {
2497  grn_rc rc = GRN_SUCCESS;
2498  GRN_API_ENTER;
2499  switch (table->header.type) {
2500  case GRN_TABLE_PAT_KEY :
2501  {
2502  grn_pat *pat = (grn_pat *)table;
2503  WITH_NORMALIZE(pat, key, key_size, {
2504  switch (mode) {
2505  case GRN_OP_EXACT :
2506  {
2507  grn_id id = grn_pat_get(ctx, pat, key, key_size, NULL);
2508  if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2509  }
2510  // todo : support op;
2511  break;
2512  case GRN_OP_LCP :
2513  {
2514  grn_id id = grn_pat_lcp_search(ctx, pat, key, key_size);
2515  if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2516  }
2517  // todo : support op;
2518  break;
2519  case GRN_OP_SUFFIX :
2520  rc = grn_pat_suffix_search(ctx, pat, key, key_size, (grn_hash *)res);
2521  // todo : support op;
2522  break;
2523  case GRN_OP_PREFIX :
2524  rc = grn_pat_prefix_search(ctx, pat, key, key_size, (grn_hash *)res);
2525  // todo : support op;
2526  break;
2527  case GRN_OP_TERM_EXTRACT :
2528  {
2529  int len;
2530  grn_id tid;
2531  const char *sp = key;
2532  const char *se = sp + key_size;
2533  for (; sp < se; sp += len) {
2534  if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
2535  grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
2536  /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
2537  }
2538  if (!(len = grn_charlen(ctx, sp, se))) { break; }
2539  }
2540  }
2541  // todo : support op;
2542  break;
2543  default :
2544  rc = GRN_INVALID_ARGUMENT;
2545  ERR(rc, "invalid mode %d", mode);
2546  }
2547  });
2548  }
2549  break;
2550  case GRN_TABLE_DAT_KEY :
2551  {
2552  grn_dat *dat = (grn_dat *)table;
2553  WITH_NORMALIZE(dat, key, key_size, {
2554  switch (mode) {
2555  case GRN_OP_EXACT :
2556  {
2557  grn_id id = grn_dat_get(ctx, dat, key, key_size, NULL);
2558  if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2559  }
2560  break;
2561  case GRN_OP_PREFIX :
2562  {
2563  grn_dat_cursor *dc = grn_dat_cursor_open(ctx, dat, key, key_size, NULL, 0,
2564  0, -1, GRN_CURSOR_PREFIX);
2565  if (dc) {
2566  grn_id id;
2567  while ((id = grn_dat_cursor_next(ctx, dc))) {
2568  grn_table_add(ctx, res, &id, sizeof(grn_id), NULL);
2569  }
2570  grn_dat_cursor_close(ctx, dc);
2571  }
2572  }
2573  break;
2574  case GRN_OP_LCP :
2575  {
2576  grn_id id = grn_dat_lcp_search(ctx, dat, key, key_size);
2577  if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2578  }
2579  break;
2580  case GRN_OP_TERM_EXTRACT :
2581  {
2582  int len;
2583  grn_id tid;
2584  const char *sp = key;
2585  const char *se = sp + key_size;
2586  for (; sp < se; sp += len) {
2587  if ((tid = grn_dat_lcp_search(ctx, dat, sp, se - sp))) {
2588  grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
2589  /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
2590  }
2591  if (!(len = grn_charlen(ctx, sp, se))) { break; }
2592  }
2593  }
2594  // todo : support op;
2595  break;
2596  default :
2597  rc = GRN_INVALID_ARGUMENT;
2598  ERR(rc, "invalid mode %d", mode);
2599  }
2600  });
2601  }
2602  break;
2603  case GRN_TABLE_HASH_KEY :
2604  {
2605  grn_hash *hash = (grn_hash *)table;
2606  grn_id id = GRN_ID_NIL;
2607  WITH_NORMALIZE(hash, key, key_size, {
2608  id = grn_hash_get(ctx, hash, key, key_size, NULL);
2609  });
2610  if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2611  }
2612  break;
2613  }
2614  GRN_API_RETURN(rc);
2615 }
2616 
2617 grn_id
2619 {
2620  grn_id r = GRN_ID_NIL;
2621  GRN_API_ENTER;
2622  if (table) {
2623  switch (table->header.type) {
2624  case GRN_TABLE_PAT_KEY :
2625  r = grn_pat_next(ctx, (grn_pat *)table, id);
2626  break;
2627  case GRN_TABLE_DAT_KEY :
2628  r = grn_dat_next(ctx, (grn_dat *)table, id);
2629  break;
2630  case GRN_TABLE_HASH_KEY :
2631  r = grn_hash_next(ctx, (grn_hash *)table, id);
2632  break;
2633  case GRN_TABLE_NO_KEY :
2634  r = grn_array_next(ctx, (grn_array *)table, id);
2635  break;
2636  }
2637  }
2638  GRN_API_RETURN(r);
2639 }
2640 
2641 grn_rc
2642 grn_accessor_resolve(grn_ctx *ctx, grn_obj *accessor, int deep,
2643  grn_obj *base_res, grn_obj *res, grn_operator op,
2644  grn_search_optarg *optarg)
2645 {
2646  grn_rc rc = GRN_SUCCESS;
2647  grn_accessor *a;
2648  grn_obj accessor_stack;
2649  int i, n_accessors;
2650  grn_obj *current_res = base_res;
2651 
2652  GRN_PTR_INIT(&accessor_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
2653  n_accessors = 0;
2654  for (a = (grn_accessor *)accessor; a; a = a->next) {
2655  if (deep == n_accessors) {
2656  break;
2657  }
2658  GRN_PTR_PUT(ctx, &accessor_stack, a);
2659  n_accessors++;
2660  }
2661 
2662  for (i = n_accessors; i > 0; i--) {
2663  grn_obj *index;
2664  grn_operator index_op = GRN_OP_MATCH;
2665 
2666  a = (grn_accessor *)GRN_PTR_VALUE_AT(&accessor_stack, i - 1);
2667  if (grn_column_index(ctx, a->obj, index_op, &index, 1, NULL) == 0) {
2668  rc = GRN_INVALID_ARGUMENT;
2669  break;
2670  }
2671 
2672  {
2673  grn_id *tid;
2674  grn_obj *domain;
2675  grn_obj *next_res;
2676  grn_search_optarg next_optarg;
2677  grn_rset_recinfo *recinfo;
2678  if (optarg) {
2679  next_optarg = *optarg;
2680  next_optarg.mode = GRN_OP_EXACT;
2681  } else {
2682  memset(&next_optarg, 0, sizeof(grn_search_optarg));
2683  }
2684  {
2685  grn_obj *range = grn_ctx_at(ctx, DB_OBJ(index)->range);
2686  next_res = grn_table_create(ctx, NULL, 0, NULL,
2687  GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
2688  range, NULL);
2689  rc = ctx->rc;
2690  grn_obj_unlink(ctx, range);
2691  if (!next_res) {
2692  if (current_res != base_res) {
2693  grn_obj_unlink(ctx, current_res);
2694  }
2695  break;
2696  }
2697  }
2698  domain = grn_ctx_at(ctx, index->header.domain);
2699  GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &tid, NULL, &recinfo, {
2700  next_optarg.weight_vector = NULL;
2701  next_optarg.vector_size = recinfo->score;
2702  if (domain->header.type == GRN_TABLE_NO_KEY) {
2703  rc = grn_ii_sel(ctx, (grn_ii *)index,
2704  (const char *)tid, sizeof(grn_id),
2705  (grn_hash *)next_res, GRN_OP_OR,
2706  &next_optarg);
2707  } else {
2708  char key[GRN_TABLE_MAX_KEY_SIZE];
2709  int key_len;
2710  key_len = grn_table_get_key(ctx, domain, *tid,
2711  key, GRN_TABLE_MAX_KEY_SIZE);
2712  rc = grn_ii_sel(ctx, (grn_ii *)index, key, key_len,
2713  (grn_hash *)next_res, GRN_OP_OR,
2714  &next_optarg);
2715  }
2716  if (rc != GRN_SUCCESS) {
2717  break;
2718  }
2719  });
2720  grn_obj_unlink(ctx, domain);
2721  if (current_res != base_res) {
2722  grn_obj_unlink(ctx, current_res);
2723  }
2724  if (rc != GRN_SUCCESS) {
2725  grn_obj_unlink(ctx, next_res);
2726  break;
2727  }
2728  current_res = next_res;
2729  }
2730  }
2731 
2732  if (rc == GRN_SUCCESS) {
2733  rc = grn_table_setoperation(ctx, res, current_res, res, op);
2734  }
2735 
2736  if (current_res != base_res) {
2737  grn_obj_unlink(ctx, current_res);
2738  }
2739 
2740  GRN_OBJ_FIN(ctx, &accessor_stack);
2741  return rc;
2742 }
2743 
2744 static inline grn_rc
2745 grn_obj_search_accessor(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
2746  grn_obj *res, grn_operator op, grn_search_optarg *optarg)
2747 {
2748  grn_rc rc = GRN_SUCCESS;
2749  grn_accessor *a;
2750  grn_obj *last_obj = NULL;
2751  int n_accessors;
2752 
2753  for (a = (grn_accessor *)obj; a; a = a->next) {
2754  if (!a->next) {
2755  last_obj = a->obj;
2756  }
2757  }
2758  n_accessors = 0;
2759  for (a = (grn_accessor *)obj; a; a = a->next) {
2760  n_accessors++;
2761  if (a->obj->header.type == GRN_COLUMN_INDEX) {
2762  break;
2763  }
2764  }
2765 
2766  {
2767  grn_obj *index;
2768  grn_operator index_op = GRN_OP_MATCH;
2769  if (optarg && optarg->mode != GRN_OP_EXACT) {
2770  index_op = optarg->mode;
2771  }
2772  if (grn_column_index(ctx, last_obj, index_op, &index, 1, NULL) == 0) {
2773  rc = GRN_INVALID_ARGUMENT;
2774  goto exit;
2775  }
2776 
2777  if (n_accessors == 1) {
2778  rc = grn_obj_search(ctx, index, query, res, op, optarg);
2779  } else {
2780  grn_obj *base_res;
2781  grn_obj *range = grn_ctx_at(ctx, DB_OBJ(index)->range);
2782  base_res = grn_table_create(ctx, NULL, 0, NULL,
2783  GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
2784  range,
2785  NULL);
2786  rc = ctx->rc;
2787  grn_obj_unlink(ctx, range);
2788  if (!base_res) {
2789  goto exit;
2790  }
2791  rc = grn_obj_search(ctx, index, query, base_res, GRN_OP_OR, optarg);
2792  if (rc != GRN_SUCCESS) {
2793  grn_obj_unlink(ctx, base_res);
2794  goto exit;
2795  }
2796  rc = grn_accessor_resolve(ctx, obj, n_accessors - 1, base_res, res, op,
2797  optarg);
2798  grn_obj_unlink(ctx, base_res);
2799  }
2800  }
2801 
2802 exit :
2803  return rc;
2804 }
2805 
2806 static grn_rc
2807 grn_obj_search_column_index(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
2808  grn_obj *res, grn_operator op,
2809  grn_search_optarg *optarg)
2810 {
2812 
2813  if (DB_OBJ(obj)->range == res->header.domain) {
2814  switch (query->header.type) {
2815  case GRN_BULK :
2816  if (query->header.domain == obj->header.domain &&
2817  GRN_BULK_VSIZE(query) == sizeof(grn_id)) {
2818  grn_id tid = *((grn_id *)GRN_BULK_HEAD(query));
2819  grn_ii_cursor *c = grn_ii_cursor_open(ctx, (grn_ii *)obj, tid,
2820  GRN_ID_NIL, GRN_ID_MAX, 1, 0);
2821  if (c) {
2822  grn_ii_posting *pos;
2823  grn_hash *s = (grn_hash *)res;
2824  while ((pos = grn_ii_cursor_next(ctx, c))) {
2825  /* todo: support orgarg(op)
2826  res_add(ctx, s, (grn_rset_posinfo *) pos,
2827  get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg), op);
2828  */
2829  grn_hash_add(ctx, s, pos, s->key_size, NULL, NULL);
2830  }
2831  grn_ii_cursor_close(ctx, c);
2832  }
2833  return GRN_SUCCESS;
2834  } else {
2835  unsigned int key_type = GRN_ID_NIL;
2836  const char *key;
2837  unsigned int key_len;
2838  grn_obj *table;
2839  grn_obj casted_query;
2840  grn_bool need_cast = GRN_FALSE;
2841 
2842  table = grn_ctx_at(ctx, obj->header.domain);
2843  if (table) {
2844  key_type = table->header.domain;
2845  need_cast = (query->header.domain != key_type);
2846  grn_obj_unlink(ctx, table);
2847  }
2848  if (need_cast) {
2849  GRN_OBJ_INIT(&casted_query, GRN_BULK, 0, key_type);
2850  rc = grn_obj_cast(ctx, query, &casted_query, GRN_FALSE);
2851  if (rc == GRN_SUCCESS) {
2852  key = GRN_BULK_HEAD(&casted_query);
2853  key_len = GRN_BULK_VSIZE(&casted_query);
2854  }
2855  } else {
2856  rc = GRN_SUCCESS;
2857  key = GRN_BULK_HEAD(query);
2858  key_len = GRN_BULK_VSIZE(query);
2859  }
2860  if (rc == GRN_SUCCESS) {
2861  rc = grn_ii_sel(ctx, (grn_ii *)obj, key, key_len,
2862  (grn_hash *)res, op, optarg);
2863  }
2864  if (need_cast) {
2865  GRN_OBJ_FIN(ctx, &casted_query);
2866  }
2867  }
2868  break;
2869  case GRN_QUERY :
2871  break;
2872  }
2873  }
2874 
2875  return rc;
2876 }
2877 
2878 grn_rc
2880  grn_obj *res, grn_operator op, grn_search_optarg *optarg)
2881 {
2883  GRN_API_ENTER;
2884  if (GRN_ACCESSORP(obj)) {
2885  rc = grn_obj_search_accessor(ctx, obj, query, res, op, optarg);
2886  } else if (GRN_DB_OBJP(obj)) {
2887  switch (obj->header.type) {
2888  case GRN_TABLE_PAT_KEY :
2889  case GRN_TABLE_DAT_KEY :
2890  case GRN_TABLE_HASH_KEY :
2891  {
2892  const void *key = GRN_BULK_HEAD(query);
2893  uint32_t key_size = GRN_BULK_VSIZE(query);
2894  grn_operator mode = optarg ? optarg->mode : GRN_OP_EXACT;
2895  if (!key || !key_size) {
2896  return GRN_INVALID_ARGUMENT;
2897  }
2898  rc = grn_table_search(ctx, obj, key, key_size, mode, res, op);
2899  }
2900  break;
2901  case GRN_COLUMN_INDEX :
2902  rc = grn_obj_search_column_index(ctx, obj, query, res, op, optarg);
2903  break;
2904  }
2905  }
2906  GRN_API_RETURN(rc);
2907 }
2908 
2909 #define GRN_TABLE_GROUP_BY_KEY 0
2910 #define GRN_TABLE_GROUP_BY_VALUE 1
2911 #define GRN_TABLE_GROUP_BY_COLUMN_VALUE 2
2912 
2913 #define GRN_TABLE_GROUP_FILTER_PREFIX 0
2914 #define GRN_TABLE_GROUP_FILTER_SUFFIX (1L<<2)
2915 
2916 static int
2917 accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key, grn_obj *res)
2918 {
2919  if (key->header.type == GRN_ACCESSOR) {
2920  grn_accessor *a = (grn_accessor *)key;
2921  if (a->action == GRN_ACCESSOR_GET_KEY &&
2923  a->next->obj && !a->next->next) {
2924  grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
2925  int idp = GRN_OBJ_TABLEP(range);
2926  grn_table_cursor *tc;
2927  if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
2928  switch (a->next->obj->header.type) {
2929  case GRN_COLUMN_FIX_SIZE :
2930  {
2931  grn_id id;
2932  grn_ra *ra = (grn_ra *)a->next->obj;
2933  unsigned int element_size = (ra)->header->element_size;
2934  grn_ra_cache cache;
2935  GRN_RA_CACHE_INIT(ra, &cache);
2936  while ((id = grn_table_cursor_next_inline(ctx, tc))) {
2937  void *v, *value;
2938  grn_id *id_;
2939  uint32_t key_size;
2940  grn_rset_recinfo *ri = NULL;
2941  if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
2942  grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
2943  }
2944  id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
2945  v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
2946  if (idp && *((grn_id *)v) &&
2947  grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
2948  continue;
2949  }
2950  if ((!idp || *((grn_id *)v)) &&
2951  grn_table_add_v_inline(ctx, res, v, element_size, &value, NULL)) {
2952  grn_table_add_subrec_inline(res, value, ri ? ri->score : 0,
2953  (grn_rset_posinfo *)&id, 0);
2954  }
2955  }
2956  GRN_RA_CACHE_FIN(ra, &cache);
2957  }
2958  break;
2959  case GRN_COLUMN_VAR_SIZE :
2960  if (idp) { /* todo : support other type */
2961  grn_id id;
2962  grn_ja *ja = (grn_ja *)a->next->obj;
2963  while ((id = grn_table_cursor_next_inline(ctx, tc))) {
2964  grn_io_win jw;
2965  unsigned int len = 0;
2966  void *value;
2967  grn_id *v, *id_;
2968  uint32_t key_size;
2969  grn_rset_recinfo *ri = NULL;
2970  if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
2971  grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
2972  }
2973  id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
2974  if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
2975  while (len) {
2976  if ((*v != GRN_ID_NIL) &&
2977  grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
2978  grn_table_add_subrec_inline(res, value, ri ? ri->score : 0,
2979  (grn_rset_posinfo *)&id, 0);
2980  }
2981  v++;
2982  len -= sizeof(grn_id);
2983  }
2984  grn_ja_unref(ctx, &jw);
2985  }
2986  }
2987  } else {
2988  return 0;
2989  }
2990  break;
2991  default :
2992  return 0;
2993  }
2994  grn_table_cursor_close(ctx, tc);
2995  return 1;
2996  }
2997  }
2998  }
2999  return 0;
3000 }
3001 
3002 grn_rc
3004  grn_table_sort_key *group_key,
3005  grn_obj *res, uint32_t range_gap)
3006 {
3007  grn_obj *key = group_key->key;
3008  if (key->header.type == GRN_ACCESSOR) {
3009  grn_accessor *a = (grn_accessor *)key;
3010  if (a->action == GRN_ACCESSOR_GET_KEY &&
3012  a->next->obj && !a->next->next) {
3013  grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
3014  int idp = GRN_OBJ_TABLEP(range);
3015  grn_table_cursor *tc;
3016  if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL,
3017  0, 0, -1, 0))) {
3018  switch (a->next->obj->header.type) {
3019  case GRN_COLUMN_FIX_SIZE :
3020  {
3021  grn_id id;
3022  grn_ra *ra = (grn_ra *)a->next->obj;
3023  unsigned int element_size = (ra)->header->element_size;
3024  grn_ra_cache cache;
3025  GRN_RA_CACHE_INIT(ra, &cache);
3026  while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3027  void *v, *value;
3028  grn_id *id_;
3029  uint32_t key_size;
3030  grn_rset_recinfo *ri = NULL;
3031  if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3032  grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3033  }
3034  id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
3035  v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
3036  if (idp && *((grn_id *)v) &&
3037  grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
3038  continue;
3039  }
3040  if ((!idp || *((grn_id *)v))) {
3041  grn_id id;
3042  if (element_size == sizeof(uint32_t)) {
3043  uint32_t quantized = (*(uint32_t *)v);
3044  quantized -= quantized % range_gap;
3045  id = grn_table_add_v_inline(ctx, res, &quantized,
3046  element_size, &value, NULL);
3047  } else {
3048  id = grn_table_add_v_inline(ctx, res, v,
3049  element_size, &value, NULL);
3050  }
3051  if (id) {
3052  grn_table_add_subrec_inline(res, value,
3053  ri ? ri->score : 0,
3054  (grn_rset_posinfo *)&id, 0);
3055  }
3056  }
3057  }
3058  GRN_RA_CACHE_FIN(ra, &cache);
3059  }
3060  break;
3061  case GRN_COLUMN_VAR_SIZE :
3062  if (idp) { /* todo : support other type */
3063  grn_id id;
3064  grn_ja *ja = (grn_ja *)a->next->obj;
3065  while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3066  grn_io_win jw;
3067  unsigned int len = 0;
3068  void *value;
3069  grn_id *v, *id_;
3070  uint32_t key_size;
3071  grn_rset_recinfo *ri = NULL;
3072  if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3073  grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3074  }
3075  id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
3076  if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
3077  while (len) {
3078  if ((*v != GRN_ID_NIL) &&
3079  grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
3080  grn_table_add_subrec_inline(res, value, ri ? ri->score : 0,
3081  (grn_rset_posinfo *)&id, 0);
3082  }
3083  v++;
3084  len -= sizeof(grn_id);
3085  }
3086  grn_ja_unref(ctx, &jw);
3087  }
3088  }
3089  } else {
3090  return 0;
3091  }
3092  break;
3093  default :
3094  return 0;
3095  }
3096  grn_table_cursor_close(ctx, tc);
3097  GRN_TABLE_GROUPED_ON(res);
3098  return 1;
3099  }
3100  }
3101  }
3102  return 0;
3103 }
3104 
3105 grn_rc
3107  grn_table_sort_key *keys, int n_keys,
3108  grn_table_group_result *results, int n_results)
3109 {
3110  grn_rc rc = GRN_SUCCESS;
3111  if (!table || !n_keys || !n_results) {
3112  ERR(GRN_INVALID_ARGUMENT, "table or n_keys or n_results is void");
3113  return GRN_INVALID_ARGUMENT;
3114  }
3115  GRN_API_ENTER;
3116  {
3117  int k, r;
3118  void *key;
3119  grn_obj bulk;
3120  grn_table_cursor *tc;
3121  grn_table_sort_key *kp;
3123  for (k = 0, kp = keys; k < n_keys; k++, kp++) {
3124  if ((kp->flags & GRN_TABLE_GROUP_BY_COLUMN_VALUE) && !kp->key) {
3125  ERR(GRN_INVALID_ARGUMENT, "column missing in (%d)", k);
3126  goto exit;
3127  }
3128  }
3129  for (r = 0, rp = results; r < n_results; r++, rp++) {
3130  if (!rp->table) {
3131  ERR(GRN_INVALID_ARGUMENT, "table missing in (%d)", r);
3132  goto exit;
3133  }
3134  }
3135  GRN_TEXT_INIT(&bulk, 0);
3136  if (n_keys == 1 && n_results == 1) {
3137  if (!accelerated_table_group(ctx, table, keys->key, results->table)) {
3138  if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3139  grn_id id;
3140  grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, keys->key));
3141  int idp = GRN_OBJ_TABLEP(range);
3142  while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3143  void *value;
3144  grn_rset_recinfo *ri = NULL;
3145  GRN_BULK_REWIND(&bulk);
3146  if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3147  grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3148  }
3149  grn_obj_get_value(ctx, keys->key, id, &bulk);
3150  switch (bulk.header.type) {
3151  case GRN_UVECTOR :
3152  {
3153  // todo : support objects except grn_id
3154  grn_id *v = (grn_id *)GRN_BULK_HEAD(&bulk);
3155  grn_id *ve = (grn_id *)GRN_BULK_CURR(&bulk);
3156  while (v < ve) {
3157  if ((*v != GRN_ID_NIL) &&
3158  grn_table_add_v_inline(ctx, results->table, v, sizeof(grn_id), &value, NULL)) {
3159  grn_table_add_subrec_inline(results->table, value, ri ? ri->score : 0,
3160  (grn_rset_posinfo *)&id, 0);
3161  }
3162  v++;
3163  }
3164  }
3165  break;
3166  case GRN_VECTOR :
3167  ERR(GRN_OPERATION_NOT_SUPPORTED, "sorry.. not implemented yet");
3168  /* todo */
3169  break;
3170  case GRN_BULK :
3171  {
3172  if ((!idp || *((grn_id *)GRN_BULK_HEAD(&bulk))) &&
3173  grn_table_add_v_inline(ctx, results->table,
3174  GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk), &value, NULL)) {
3175  grn_table_add_subrec_inline(results->table, value, ri ? ri->score : 0,
3176  (grn_rset_posinfo *)&id, 0);
3177  }
3178  }
3179  break;
3180  default :
3181  ERR(GRN_INVALID_ARGUMENT, "invalid column");
3182  break;
3183  }
3184  }
3185  grn_table_cursor_close(ctx, tc);
3186  }
3187  }
3188  } else {
3189  if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3190  grn_id id;
3191  while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3192  grn_rset_recinfo *ri = NULL;
3193  GRN_BULK_REWIND(&bulk);
3194  if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3195  grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3196  }
3197  for (k = 0, kp = keys; k < n_keys; k++, kp++) {
3198  kp->offset = GRN_BULK_VSIZE(&bulk);
3199  grn_obj_get_value(ctx, kp->key, id, &bulk);
3200  }
3201  for (r = 0, rp = results; r < n_results; r++, rp++) {
3202  void *value;
3203  int begin = keys[rp->key_begin].offset;
3204  int end = rp->key_end >= n_keys
3205  ? GRN_BULK_VSIZE(&bulk)
3206  : keys[rp->key_end].offset;
3207  key = GRN_BULK_HEAD(&bulk) + begin;
3208  // todo : cut off GRN_ID_NIL
3209  if (grn_table_add_v_inline(ctx, rp->table, key, end - begin, &value, NULL)) {
3210  grn_table_add_subrec_inline(rp->table, value, ri ? ri->score : 0,
3211  (grn_rset_posinfo *)&id, 0);
3212  }
3213  }
3214  }
3215  grn_table_cursor_close(ctx, tc);
3216  }
3217  }
3218  grn_obj_close(ctx, &bulk);
3219  for (r = 0, rp = results; r < n_results; r++, rp++) {
3221  }
3222  }
3223 exit :
3224  GRN_API_RETURN(rc);
3225 }
3226 
3227 grn_rc
3229  grn_operator op)
3230 {
3231  grn_rc rc = GRN_SUCCESS;
3232  void *key = NULL, *value1 = NULL, *value2 = NULL;
3233  uint32_t value_size = 0;
3234  uint32_t key_size = 0;
3235  grn_bool have_subrec;
3236  if (table1 != res) {
3237  if (table2 == res) {
3238  grn_obj *t = table1;
3239  table1 = table2;
3240  table2 = t;
3241  } else {
3242  return GRN_INVALID_ARGUMENT;
3243  }
3244  }
3245  have_subrec = ((DB_OBJ(table1)->header.flags & GRN_OBJ_WITH_SUBREC) &&
3246  (DB_OBJ(table2)->header.flags & GRN_OBJ_WITH_SUBREC));
3247  switch (table1->header.type) {
3248  case GRN_TABLE_HASH_KEY :
3249  value_size = ((grn_hash *)table1)->value_size;
3250  break;
3251  case GRN_TABLE_PAT_KEY :
3252  value_size = ((grn_pat *)table1)->value_size;
3253  break;
3254  case GRN_TABLE_DAT_KEY :
3255  value_size = 0;
3256  break;
3257  case GRN_TABLE_NO_KEY :
3258  value_size = ((grn_array *)table1)->value_size;
3259  break;
3260  }
3261  switch (table2->header.type) {
3262  case GRN_TABLE_HASH_KEY :
3263  if (value_size < ((grn_hash *)table2)->value_size) {
3264  value_size = ((grn_hash *)table2)->value_size;
3265  }
3266  break;
3267  case GRN_TABLE_PAT_KEY :
3268  if (value_size < ((grn_pat *)table2)->value_size) {
3269  value_size = ((grn_pat *)table2)->value_size;
3270  }
3271  break;
3272  case GRN_TABLE_DAT_KEY :
3273  value_size = 0;
3274  break;
3275  case GRN_TABLE_NO_KEY :
3276  if (value_size < ((grn_array *)table2)->value_size) {
3277  value_size = ((grn_array *)table2)->value_size;
3278  }
3279  break;
3280  }
3281  switch (op) {
3282  case GRN_OP_OR :
3283  if (have_subrec) {
3284  int added;
3285  GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
3286  if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, &added)) {
3287  if (added) {
3288  memcpy(value1, value2, value_size);
3289  } else {
3290  grn_rset_recinfo *ri1 = value1;
3291  grn_rset_recinfo *ri2 = value2;
3292  grn_table_add_subrec_inline(table1, ri1, ri2->score, NULL, 0);
3293  }
3294  }
3295  });
3296  } else {
3297  GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
3298  if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, NULL)) {
3299  memcpy(value1, value2, value_size);
3300  }
3301  });
3302  }
3303  break;
3304  case GRN_OP_AND :
3305  if (have_subrec) {
3306  GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
3307  if (grn_table_get_v(ctx, table2, key, key_size, &value2)) {
3308  grn_rset_recinfo *ri1 = value1;
3309  grn_rset_recinfo *ri2 = value2;
3310  ri1->score += ri2->score;
3311  } else {
3312  _grn_table_delete_by_id(ctx, table1, id, NULL);
3313  }
3314  });
3315  } else {
3316  GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
3317  if (!grn_table_get_v(ctx, table2, key, key_size, &value2)) {
3318  _grn_table_delete_by_id(ctx, table1, id, NULL);
3319  }
3320  });
3321  }
3322  break;
3323  case GRN_OP_AND_NOT :
3324  GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
3325  grn_table_delete(ctx, table1, key, key_size);
3326  });
3327  break;
3328  case GRN_OP_ADJUST :
3329  GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
3330  if (grn_table_get_v(ctx, table1, key, key_size, &value1)) {
3331  memcpy(value1, value2, value_size);
3332  }
3333  });
3334  break;
3335  default :
3336  break;
3337  }
3338  return rc;
3339 }
3340 
3341 grn_rc
3343  grn_obj *res1, grn_obj *res2)
3344 {
3345  void *key = NULL;
3346  uint32_t key_size = 0;
3347  if (table1 != res1 || table2 != res2) { return GRN_INVALID_ARGUMENT; }
3348  if (grn_table_size(ctx, table1) > grn_table_size(ctx, table2)) {
3349  GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, NULL, {
3350  grn_id id1;
3351  if ((id1 = grn_table_get(ctx, table1, key, key_size))) {
3352  _grn_table_delete_by_id(ctx, table1, id1, NULL);
3353  _grn_table_delete_by_id(ctx, table2, id, NULL);
3354  }
3355  });
3356  } else {
3357  GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, NULL, {
3358  grn_id id2;
3359  if ((id2 = grn_table_get(ctx, table2, key, key_size))) {
3360  _grn_table_delete_by_id(ctx, table1, id, NULL);
3361  _grn_table_delete_by_id(ctx, table2, id2, NULL);
3362  }
3363  });
3364  }
3365  return GRN_SUCCESS;
3366 }
3367 
3368 static grn_obj *grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj,
3369  const char *name, unsigned int name_size);
3370 
3371 static grn_obj *
3372 grn_obj_column_(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
3373 {
3374  grn_obj *column = NULL;
3375  char buf[GRN_TABLE_MAX_KEY_SIZE];
3376  int len = grn_obj_name(ctx, table, buf, GRN_TABLE_MAX_KEY_SIZE);
3377  if (len) {
3378  buf[len++] = GRN_DB_DELIMITER;
3379  if (len + name_size <= GRN_TABLE_MAX_KEY_SIZE) {
3380  memcpy(buf + len, name, name_size);
3381  column = grn_ctx_get(ctx, buf, len + name_size);
3382  } else {
3383  ERR(GRN_INVALID_ARGUMENT, "name is too long");
3384  }
3385  } else {
3386  /* todo : support temporary table */
3387  }
3388  return column;
3389 }
3390 
3391 grn_obj *
3392 grn_obj_column(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
3393 {
3394  grn_obj *column = NULL;
3395  GRN_API_ENTER;
3396  if (GRN_OBJ_TABLEP(table)) {
3397  if (grn_db_check_name(ctx, name, name_size) ||
3398  !(column = grn_obj_column_(ctx, table, name, name_size))) {
3399  column = grn_obj_get_accessor(ctx, table, name, name_size);
3400  }
3401  } else if (GRN_ACCESSORP(table)) {
3402  column = grn_obj_get_accessor(ctx, table, name, name_size);
3403  }
3404  GRN_API_RETURN(column);
3405 }
3406 
3407 int
3408 grn_table_columns(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size,
3409  grn_obj *res)
3410 {
3411  int n = 0;
3412  GRN_API_ENTER;
3413  if (GRN_OBJ_TABLEP(table) && DB_OBJ(table)->id &&
3414  !(DB_OBJ(table)->id & GRN_OBJ_TMP_OBJECT)) {
3415  grn_db *s = (grn_db *)DB_OBJ(table)->db;
3416  if (s->keys) {
3417  grn_obj bulk;
3418  GRN_TEXT_INIT(&bulk, 0);
3419  grn_table_get_key2(ctx, s->keys, DB_OBJ(table)->id, &bulk);
3420  GRN_TEXT_PUTC(ctx, &bulk, GRN_DB_DELIMITER);
3421  grn_bulk_write(ctx, &bulk, name, name_size);
3422  grn_table_search(ctx, s->keys, GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
3423  GRN_OP_PREFIX, res, GRN_OP_OR);
3424  grn_obj_close(ctx, &bulk);
3425  n = grn_table_size(ctx, res);
3426  }
3427  }
3428  GRN_API_RETURN(n);
3429 }
3430 
3431 const char *
3432 _grn_table_key(grn_ctx *ctx, grn_obj *table, grn_id id, uint32_t *key_size)
3433 {
3434  GRN_ASSERT(table);
3435  if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
3436  switch (table->header.type) {
3437  case GRN_TABLE_HASH_KEY :
3438  return _grn_hash_key(ctx, (grn_hash *)table, id, key_size);
3439  case GRN_TABLE_PAT_KEY :
3440  return _grn_pat_key(ctx, (grn_pat *)table, id, key_size);
3441  case GRN_TABLE_DAT_KEY :
3442  return _grn_dat_key(ctx, (grn_dat *)table, id, key_size);
3443  case GRN_TABLE_NO_KEY :
3444  {
3445  grn_array *a = (grn_array *)table;
3446  const char *v;
3447  if (a->obj.header.domain && a->value_size &&
3448  (v = _grn_array_get_value(ctx, a, id))) {
3449  *key_size = a->value_size;
3450  return v;
3451  } else {
3452  *key_size = 0;
3453  }
3454  }
3455  break;
3456  }
3457  return NULL;
3458 }
3459 
3460 /* column */
3461 
3462 grn_obj *
3464  const char *name, unsigned int name_size,
3465  const char *path, grn_obj_flags flags, grn_obj *type)
3466 {
3467  grn_db *s;
3468  uint32_t value_size;
3469  grn_obj *db, *res = NULL;
3470  grn_id id = GRN_ID_NIL;
3471  grn_id range = GRN_ID_NIL;
3472  grn_id domain = GRN_ID_NIL;
3473  char fullname[GRN_TABLE_MAX_KEY_SIZE];
3474  char buffer[PATH_MAX];
3475  grn_bool ja_p = GRN_FALSE;
3476  GRN_API_ENTER;
3477  if (!table) {
3478  ERR(GRN_INVALID_ARGUMENT, "[column][create] table is missing");
3479  goto exit;
3480  }
3481  if (!type) {
3482  ERR(GRN_INVALID_ARGUMENT, "[column][create] type is missing");
3483  goto exit;
3484  }
3485  if (!name || !name_size) {
3486  ERR(GRN_INVALID_ARGUMENT, "[column][create] name is missing");
3487  goto exit;
3488  }
3489  db = DB_OBJ(table)->db;
3490  s = (grn_db *)db;
3491  if (!GRN_DB_P(s)) {
3492  int table_name_len;
3493  char table_name[GRN_TABLE_MAX_KEY_SIZE];
3494  table_name_len = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
3496  "[column][create] invalid db assigned: <%.*s>.<%.*s>",
3497  table_name_len, table_name, name_size, name);
3498  goto exit;
3499  }
3500  if (DB_OBJ(table)->id & GRN_OBJ_TMP_OBJECT) {
3502  "[column][create] temporary table doesn't support column: <%.*s>",
3503  name_size, name);
3504  goto exit;
3505  }
3506  {
3507  uint32_t s = 0;
3508  const char *n = _grn_table_key(ctx, ctx->impl->db, DB_OBJ(table)->id, &s);
3509  GRN_LOG(ctx, GRN_LOG_NOTICE,
3510  "DDL:column_create %.*s %.*s", s, n, name_size, name);
3511  }
3512  if (grn_db_check_name(ctx, name, name_size)) {
3513  GRN_DB_CHECK_NAME_ERR("[column][create]", name, name_size);
3514  goto exit;
3515  }
3516  if ((domain = DB_OBJ(table)->id)) {
3517  int len = grn_table_get_key(ctx, s->keys, domain, fullname, GRN_TABLE_MAX_KEY_SIZE);
3518  if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
3520  "[column][create] too long column name: required name_size(%d) < %d"
3521  ": <%.*s>.<%.*s>",
3522  name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - len,
3523  len, fullname, name_size, name);
3524  goto exit;
3525  }
3526  fullname[len] = GRN_DB_DELIMITER;
3527  memcpy(fullname + len + 1, name, name_size);
3528  name_size += len + 1;
3529  } else {
3531  "[column][create] [todo] table-less column isn't supported yet");
3532  goto exit;
3533  }
3534  range = DB_OBJ(type)->id;
3535  switch (type->header.type) {
3536  case GRN_TYPE :
3537  {
3538  grn_db_obj *t = (grn_db_obj *)type;
3539  flags |= t->header.flags;
3540  value_size = GRN_TYPE_SIZE(t);
3541  }
3542  break;
3543  case GRN_TABLE_HASH_KEY :
3544  case GRN_TABLE_PAT_KEY :
3545  case GRN_TABLE_DAT_KEY :
3546  case GRN_TABLE_NO_KEY :
3547  value_size = sizeof(grn_id);
3548  break;
3549  default :
3550  /*
3551  if (type == grn_type_any) {
3552  value_size = sizeof(grn_id) + sizeof(grn_id);
3553  }
3554  */
3555  value_size = sizeof(grn_id);
3556  }
3557  id = grn_obj_register(ctx, db, fullname, name_size);
3558  if (ERRP(ctx, GRN_ERROR)) { goto exit; }
3559  if (GRN_OBJ_PERSISTENT & flags) {
3560  if (!path) {
3561  if (GRN_DB_PERSISTENT_P(db)) {
3562  gen_pathname(grn_obj_io(db)->path, buffer, id);
3563  path = buffer;
3564  } else {
3565  int table_name_len;
3566  char table_name[GRN_TABLE_MAX_KEY_SIZE];
3567  table_name_len = grn_obj_name(ctx, table, table_name,
3570  "[column][create] path not assigned for persistent column"
3571  ": <%.*s>.<%.*s>",
3572  table_name_len, table_name, name_size, name);
3573  goto exit;
3574  }
3575  } else {
3576  flags |= GRN_OBJ_CUSTOM_NAME;
3577  }
3578  } else {
3579  if (path) {
3580  int table_name_len;
3581  char table_name[GRN_TABLE_MAX_KEY_SIZE];
3582  table_name_len = grn_obj_name(ctx, table, table_name,
3585  "[column][create] path assigned for temporary column"
3586  ": <%.*s>.<%.*s>",
3587  table_name_len, table_name, name_size, name);
3588  goto exit;
3589  }
3590  }
3591  switch (flags & GRN_OBJ_COLUMN_TYPE_MASK) {
3592  case GRN_OBJ_COLUMN_SCALAR :
3593  if ((flags & GRN_OBJ_KEY_VAR_SIZE) || value_size > sizeof(int64_t)) {
3594  res = (grn_obj *)grn_ja_create(ctx, path, value_size, flags);
3595  ja_p = GRN_TRUE;
3596  } else {
3597  res = (grn_obj *)grn_ra_create(ctx, path, value_size);
3598  }
3599  break;
3600  case GRN_OBJ_COLUMN_VECTOR :
3601  res = (grn_obj *)grn_ja_create(ctx, path, value_size * 30/*todo*/, flags);
3602  ja_p = GRN_TRUE;
3603  //todo : zlib support
3604  break;
3605  case GRN_OBJ_COLUMN_INDEX :
3606  res = (grn_obj *)grn_ii_create(ctx, path, table, flags); //todo : ii layout support
3607  break;
3608  }
3609  if (res) {
3610  DB_OBJ(res)->header.domain = domain;
3611  DB_OBJ(res)->header.impl_flags = 0;
3612  DB_OBJ(res)->range = range;
3613  DB_OBJ(res)->header.flags = flags;
3614  res->header.flags = flags;
3615  if (ja_p) {
3616  grn_bool zlib_p = GRN_FALSE;
3617  grn_bool lzo_p = GRN_FALSE;
3618 #ifdef GRN_WITH_ZLIB
3619  if (flags & GRN_OBJ_COMPRESS_ZLIB) {
3620  zlib_p = GRN_TRUE;
3621  }
3622 #endif /* GRN_WITH_ZLIB */
3623 #ifdef GRN_WITH_LZO
3624  if (flags & GRN_OBJ_COMPRESS_LZO) {
3625  lzo_p = GRN_TRUE;
3626  }
3627 #endif /* GRN_WITH_LZO */
3628  if (zlib_p || lzo_p) {
3629  int table_name_len;
3630  char table_name[GRN_TABLE_MAX_KEY_SIZE];
3631  table_name_len = grn_obj_name(ctx, table, table_name,
3633  GRN_LOG(ctx, GRN_LOG_WARNING,
3634  "[column][create] "
3635  "%s compressed column will leaks memories: <%.*s>.<%.*s>",
3636  zlib_p ? "zlib" : "lzo",
3637  table_name_len, table_name, name_size, name);
3638  }
3639  }
3640  if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
3641  _grn_obj_remove(ctx, res);
3642  res = NULL;
3643  }
3644  grn_obj_touch(ctx, res, NULL);
3645  }
3646 exit :
3647  if (!res && id) { grn_obj_delete_by_id(ctx, db, id, GRN_TRUE); }
3648  GRN_API_RETURN(res);
3649 }
3650 
3651 grn_obj *
3653  const char *name, unsigned int name_size,
3654  const char *path, grn_obj *type)
3655 {
3656  grn_id domain;
3657  grn_obj *res = NULL;
3658  grn_db *s;
3659  char fullname[GRN_TABLE_MAX_KEY_SIZE];
3660  GRN_API_ENTER;
3661  if (!table || !type || !name || !name_size) {
3662  ERR(GRN_INVALID_ARGUMENT, "missing type or name");
3663  goto exit;
3664  }
3665  s = (grn_db *)DB_OBJ(table)->db;
3666  if (!GRN_DB_P(s)) {
3667  ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
3668  goto exit;
3669  }
3670  if (grn_db_check_name(ctx, name, name_size)) {
3671  GRN_DB_CHECK_NAME_ERR("[column][open]", name, name_size);
3672  goto exit;
3673  }
3674  if ((domain = DB_OBJ(table)->id)) {
3675  int len = grn_table_get_key(ctx, s->keys, domain, fullname, GRN_TABLE_MAX_KEY_SIZE);
3676  if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
3677  ERR(GRN_INVALID_ARGUMENT, "too long column name");
3678  goto exit;
3679  }
3680  fullname[len] = GRN_DB_DELIMITER;
3681  memcpy(fullname + len + 1, name, name_size);
3682  name_size += len + 1;
3683  } else {
3684  ERR(GRN_INVALID_ARGUMENT, "todo : not supported yet");
3685  goto exit;
3686  }
3687  res = grn_ctx_get(ctx, fullname, name_size);
3688  if (res) {
3689  const char *path2 = grn_obj_path(ctx, res);
3690  if (path && (!path2 || strcmp(path, path2))) { goto exit; }
3691  } else if (path) {
3692  uint32_t dbtype = grn_io_detect_type(ctx, path);
3693  if (!dbtype) { goto exit; }
3694  switch (dbtype) {
3695  case GRN_COLUMN_VAR_SIZE :
3696  res = (grn_obj *)grn_ja_open(ctx, path);
3697  break;
3698  case GRN_COLUMN_FIX_SIZE :
3699  res = (grn_obj *)grn_ra_open(ctx, path);
3700  break;
3701  case GRN_COLUMN_INDEX :
3702  res = (grn_obj *)grn_ii_open(ctx, path, table);
3703  break;
3704  }
3705  if (res) {
3706  grn_id id = grn_obj_register(ctx, (grn_obj *)s, fullname, name_size);
3707  DB_OBJ(res)->header.domain = domain;
3708  DB_OBJ(res)->range = DB_OBJ(type)->id;
3710  grn_db_obj_init(ctx, (grn_obj *)s, id, DB_OBJ(res));
3711  }
3712  }
3713 exit :
3714  GRN_API_RETURN(res);
3715 }
3716 
3717 /*
3718 typedef struct {
3719  grn_id id;
3720  int flags;
3721 } grn_column_set_value_arg;
3722 
3723 static grn_rc
3724 default_column_set_value(grn_ctx *ctx, grn_proc_ctx *pctx, grn_obj *in, grn_obj *out)
3725 {
3726  grn_user_data *data = grn_proc_ctx_get_local_data(pctx);
3727  if (data) {
3728  grn_column_set_value_arg *arg = data->ptr;
3729  unsigned int value_size = in->u.p.size; //todo
3730  if (!pctx->obj) { return GRN_ID_NIL; }
3731  switch (pctx->obj->header.type) {
3732  case GRN_COLUMN_VAR_SIZE :
3733  return grn_ja_put(ctx, (grn_ja *)pctx->obj, arg->id,
3734  in->u.p.ptr, value_size, 0, NULL); // todo type->flag
3735  case GRN_COLUMN_FIX_SIZE :
3736  if (((grn_ra *)pctx->obj)->header->element_size < value_size) {
3737  ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", value_size);
3738  return GRN_INVALID_ARGUMENT;
3739  } else {
3740  void *v = grn_ra_ref(ctx, (grn_ra *)pctx->obj, arg->id);
3741  if (!v) {
3742  ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
3743  return GRN_NO_MEMORY_AVAILABLE;
3744  }
3745  memcpy(v, in->u.p.ptr, value_size);
3746  grn_ra_unref(ctx, (grn_ra *)pctx->obj, arg->id);
3747  }
3748  break;
3749  case GRN_COLUMN_INDEX :
3750  // todo : how??
3751  break;
3752  }
3753  return GRN_SUCCESS;
3754  } else {
3755  ERR(GRN_OBJECT_CORRUPT, "grn_proc_ctx_get_local_data failed");
3756  return ctx->rc;
3757  }
3758 }
3759 */
3760 
3761 /**** grn_vector ****/
3762 
3763 //#define VECTOR(obj) ((grn_vector *)obj)
3764 
3765 /*
3766 #define INITIAL_VECTOR_SIZE 256
3767 
3768 int
3769 grn_vector_delimit(grn_ctx *ctx, grn_obj *vector)
3770 {
3771  grn_vector *v = VECTOR(vector);
3772  uint32_t *offsets;
3773  if (!(v->n_entries & (INITIAL_VECTOR_SIZE - 1))) {
3774  offsets = GRN_REALLOC(v->offsets, sizeof(uint32_t) *
3775  (v->n_entries + INITIAL_VECTOR_SIZE));
3776  if (!offsets) { return -1; }
3777  v->offsets = offsets;
3778  }
3779  v->offsets[v->n_entries] = GRN_BULK_VSIZE(vector);
3780  return ++(v->n_entries);
3781 }
3782 */
3783 
3784 unsigned int
3786 {
3787  unsigned int size;
3788  if (!vector) {
3789  ERR(GRN_INVALID_ARGUMENT, "vector is null");
3790  return 0;
3791  }
3792  GRN_API_ENTER;
3793  switch (vector->header.type) {
3794  case GRN_BULK :
3795  size = GRN_BULK_VSIZE(vector);
3796  break;
3797  case GRN_UVECTOR :
3798  size = GRN_BULK_VSIZE(vector) / sizeof(grn_id);
3799  break;
3800  case GRN_VECTOR :
3801  size = vector->u.v.n_sections;
3802  break;
3803  default :
3804  ERR(GRN_INVALID_ARGUMENT, "not vector");
3805  size = 0;
3806  break;
3807  }
3808  GRN_API_RETURN(size);
3809 }
3810 
3811 static grn_obj *
3812 grn_vector_body(grn_ctx *ctx, grn_obj *v)
3813 {
3814  if (!v) {
3815  ERR(GRN_INVALID_ARGUMENT, "invalid argument");
3816  return NULL;
3817  }
3818  switch (v->header.type) {
3819  case GRN_VECTOR :
3820  if (!v->u.v.body) {
3821  v->u.v.body = grn_obj_open(ctx, GRN_BULK, 0, v->header.domain);
3822  }
3823  return v->u.v.body;
3824  case GRN_BULK :
3825  case GRN_UVECTOR :
3826  return v;
3827  default :
3828  return NULL;
3829  }
3830 }
3831 
3832 unsigned int
3834  unsigned int offset, const char **str,
3835  unsigned int *weight, grn_id *domain)
3836 {
3837  unsigned int length = 0;
3838  GRN_API_ENTER;
3839  if (!vector || vector->header.type != GRN_VECTOR) {
3840  ERR(GRN_INVALID_ARGUMENT, "invalid vector");
3841  goto exit;
3842  }
3843  if (vector->u.v.n_sections <= offset) {
3844  ERR(GRN_RANGE_ERROR, "offset out of range");
3845  goto exit;
3846  }
3847  {
3848  grn_section *vp = &vector->u.v.sections[offset];
3849  grn_obj *body = grn_vector_body(ctx, vector);
3850  *str = GRN_BULK_HEAD(body) + vp->offset;
3851  if (weight) { *weight = vp->weight; }
3852  if (domain) { *domain = vp->domain; }
3853  length = vp->length;
3854  }
3855 exit :
3856  GRN_API_RETURN(length);
3857 }
3858 
3859 unsigned int
3861  const char **str, unsigned int *weight, grn_id *domain)
3862 {
3863  unsigned int offset, length = 0;
3864  GRN_API_ENTER;
3865  if (!vector || vector->header.type != GRN_VECTOR) {
3866  ERR(GRN_INVALID_ARGUMENT, "invalid vector");
3867  goto exit;
3868  }
3869  if (!vector->u.v.n_sections) {
3870  ERR(GRN_RANGE_ERROR, "offset out of range");
3871  goto exit;
3872  }
3873  offset = --vector->u.v.n_sections;
3874  {
3875  grn_section *vp = &vector->u.v.sections[offset];
3876  grn_obj *body = grn_vector_body(ctx, vector);
3877  *str = GRN_BULK_HEAD(body) + vp->offset;
3878  if (weight) { *weight = vp->weight; }
3879  if (domain) { *domain = vp->domain; }
3880  length = vp->length;
3881  grn_bulk_truncate(ctx, body, vp->offset);
3882  }
3883 exit :
3884  GRN_API_RETURN(length);
3885 }
3886 
3887 #define W_SECTIONS_UNIT 8
3888 #define S_SECTIONS_UNIT (1 << W_SECTIONS_UNIT)
3889 #define M_SECTIONS_UNIT (S_SECTIONS_UNIT - 1)
3890 
3891 grn_rc
3892 grn_vector_delimit(grn_ctx *ctx, grn_obj *v, unsigned int weight, grn_id domain)
3893 {
3894  if (v->header.type != GRN_VECTOR) { return GRN_INVALID_ARGUMENT; }
3895  if (!(v->u.v.n_sections & M_SECTIONS_UNIT)) {
3896  grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
3897  (v->u.v.n_sections + S_SECTIONS_UNIT));
3898  if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
3899  v->u.v.sections = vp;
3900  }
3901  {
3902  grn_obj *body = grn_vector_body(ctx, v);
3903  grn_section *vp = &v->u.v.sections[v->u.v.n_sections];
3904  vp->offset = v->u.v.n_sections ? vp[-1].offset + vp[-1].length : 0;
3905  vp->length = GRN_BULK_VSIZE(body) - vp->offset;
3906  vp->weight = weight;
3907  vp->domain = domain;
3908  }
3909  v->u.v.n_sections++;
3910  return GRN_SUCCESS;
3911 }
3912 
3913 grn_rc
3914 grn_vector_decode(grn_ctx *ctx, grn_obj *v, const char *data, uint32_t data_size)
3915 {
3916  uint8_t *p = (uint8_t *)data;
3917  uint8_t *pe = p + data_size;
3918  uint32_t n, n0 = v->u.v.n_sections;
3919  GRN_B_DEC(n, p);
3920  if (((n0 + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT) !=
3921  ((n0 + n + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT)) {
3922  grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
3923  ((n0 + n + M_SECTIONS_UNIT) & ~M_SECTIONS_UNIT));
3924  if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
3925  v->u.v.sections = vp;
3926  }
3927  {
3928  grn_section *vp;
3929  uint32_t o = 0, l, i;
3930  for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
3931  if (pe <= p) { return GRN_INVALID_ARGUMENT; }
3932  GRN_B_DEC(l, p);
3933  vp->length = l;
3934  vp->offset = o;
3935  vp->weight = 0;
3936  vp->domain = 0;
3937  o += l;
3938  }
3939  if (pe < p + o) { return GRN_INVALID_ARGUMENT; }
3940  {
3941  grn_obj *body = grn_vector_body(ctx, v);
3942  grn_bulk_write(ctx, body, (char *)p, o);
3943  }
3944  p += o;
3945  if (p < pe) {
3946  for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
3947  if (pe <= p) { return GRN_INVALID_ARGUMENT; }
3948  GRN_B_DEC(vp->weight, p);
3949  GRN_B_DEC(vp->domain, p);
3950  }
3951  }
3952  }
3953  v->u.v.n_sections += n;
3954  return GRN_SUCCESS;
3955 }
3956 
3957 grn_rc
3959  const char *str, unsigned int str_len,
3960  unsigned int weight, grn_id domain)
3961 {
3962  grn_obj *body;
3963  GRN_API_ENTER;
3964  if (!vector) {
3965  ERR(GRN_INVALID_ARGUMENT, "vector is null");
3966  goto exit;
3967  }
3968  if ((body = grn_vector_body(ctx, vector))) {
3969  grn_bulk_write(ctx, body, str, str_len);
3970  grn_vector_delimit(ctx, vector, weight, domain);
3971  }
3972 exit :
3973  GRN_API_RETURN(ctx->rc);
3974 }
3975 
3976 /*
3977 grn_obj *
3978 grn_sections_to_vector(grn_ctx *ctx, grn_obj *sections)
3979 {
3980  grn_obj *vector = grn_vector_open(ctx, 0);
3981  if (vector) {
3982  grn_section *vp;
3983  int i;
3984  for (i = sections->u.v.n_sections, vp = sections->u.v.sections; i; i--, vp++) {
3985  grn_text_benc(ctx, vector, vp->weight);
3986  grn_text_benc(ctx, vector, vp->domain);
3987  grn_bulk_write(ctx, vector, vp->str, vp->str_len);
3988  grn_vector_delimit(ctx, vector);
3989  }
3990  }
3991  return vector;
3992 }
3993 
3994 grn_obj *
3995 grn_vector_to_sections(grn_ctx *ctx, grn_obj *vector, grn_obj *sections)
3996 {
3997  if (!sections) {
3998  sections = grn_obj_open(ctx, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, 0);
3999  }
4000  if (sections) {
4001  int i, n = grn_vector_size(ctx, vector);
4002  sections->u.v.src = vector;
4003  for (i = 0; i < n; i++) {
4004  unsigned int size;
4005  const uint8_t *pe, *p = (uint8_t *)grn_vector_fetch(ctx, vector, i, &size);
4006  if (p) {
4007  grn_id domain;
4008  unsigned int weight;
4009  pe = p + size;
4010  if (p < pe) {
4011  GRN_B_DEC(weight, p);
4012  if (p < pe) {
4013  GRN_B_DEC(domain, p);
4014  if (p <= pe) {
4015  grn_vector_add(ctx, sections, (char *)p, pe - p, weight, domain);
4016  }
4017  }
4018  }
4019  }
4020  }
4021  }
4022  return sections;
4023 }
4024 */
4025 
4026 /**** accessor ****/
4027 
4028 static grn_accessor *
4029 accessor_new(grn_ctx *ctx)
4030 {
4032  if (res) {
4033  res->header.type = GRN_ACCESSOR;
4035  res->header.flags = 0;
4036  res->header.domain = GRN_ID_NIL;
4037  res->action = GRN_ACCESSOR_VOID;
4038  res->offset = 0;
4039  res->next = NULL;
4040  }
4041  return res;
4042 }
4043 
4044 static grn_obj *
4045 grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
4046 {
4047  grn_accessor *res = NULL, **rp = NULL, **rp0 = NULL;
4048  grn_bool is_chained = GRN_FALSE;
4049  if (!obj) { return NULL; }
4050  GRN_API_ENTER;
4051  if (obj->header.type == GRN_ACCESSOR) {
4052  is_chained = GRN_TRUE;
4053  for (rp0 = (grn_accessor **)&obj; *rp0; rp0 = &(*rp0)->next) {
4054  res = *rp0;
4055  }
4056  switch (res->action) {
4057  case GRN_ACCESSOR_GET_KEY :
4058  obj = grn_ctx_at(ctx, res->obj->header.domain);
4059  break;
4060  case GRN_ACCESSOR_GET_VALUE :
4061  case GRN_ACCESSOR_GET_SCORE :
4063  obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
4064  break;
4066  obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
4067  break;
4068  case GRN_ACCESSOR_LOOKUP :
4069  /* todo */
4070  break;
4071  case GRN_ACCESSOR_FUNCALL :
4072  /* todo */
4073  break;
4074  }
4075  }
4076  if (!obj) {
4077  res = NULL;
4078  goto exit;
4079  }
4080  {
4081  size_t len;
4082  const char *sp, *se = name + name_size;
4083  if (*name == GRN_DB_DELIMITER) { name++; }
4084  for (sp = name; (len = grn_charlen(ctx, sp, se)); sp += len) {
4085  if (*sp == GRN_DB_DELIMITER) { break; }
4086  }
4087  if (!(len = sp - name)) { goto exit; }
4088  if (*name == GRN_DB_PSEUDO_COLUMN_PREFIX) { /* pseudo column */
4089  int done = 0;
4090  if (len < 2) { goto exit; }
4091  switch (name[1]) {
4092  case 'k' : /* key */
4093  if (len != 4 || memcmp(name, "_key", 4)) { goto exit; }
4094  for (rp = &res; !done; rp = &(*rp)->next) {
4095  *rp = accessor_new(ctx);
4096  (*rp)->obj = obj;
4097  if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
4098  grn_obj_close(ctx, (grn_obj *)res);
4099  res = NULL;
4100  goto exit;
4101  }
4102  switch (obj->header.type) {
4103  case GRN_DB :
4104  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4105  rp = &(*rp)->next;
4106  *rp = accessor_new(ctx);
4107  (*rp)->obj = obj;
4108  (*rp)->action = GRN_ACCESSOR_GET_DB_OBJ;
4109  done++;
4110  break;
4111  case GRN_TYPE :
4112  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4113  done++;
4114  break;
4115  case GRN_TABLE_PAT_KEY :
4116  case GRN_TABLE_DAT_KEY :
4117  case GRN_TABLE_HASH_KEY :
4118  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4119  break;
4120  case GRN_TABLE_NO_KEY :
4121  if (obj->header.domain) {
4122  (*rp)->action = GRN_ACCESSOR_GET_VALUE;
4123  break;
4124  }
4125  /* fallthru */
4126  default :
4127  /* lookup failed */
4128  grn_obj_close(ctx, (grn_obj *)res);
4129  res = NULL;
4130  goto exit;
4131  }
4132  }
4133  break;
4134  case 'i' : /* id */
4135  if (len != 3 || memcmp(name, "_id", 3)) { goto exit; }
4136  for (rp = &res; !done; rp = &(*rp)->next) {
4137  *rp = accessor_new(ctx);
4138  (*rp)->obj = obj;
4139  if (!obj->header.domain) {
4140  (*rp)->action = GRN_ACCESSOR_GET_ID;
4141  done++;
4142  } else {
4143  if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
4144  grn_obj_close(ctx, (grn_obj *)res);
4145  res = NULL;
4146  goto exit;
4147  }
4148  switch (obj->header.type) {
4149  case GRN_DB :
4150  case GRN_TYPE :
4151  (*rp)->action = GRN_ACCESSOR_GET_ID;
4152  done++;
4153  break;
4154  case GRN_TABLE_PAT_KEY :
4155  case GRN_TABLE_DAT_KEY :
4156  case GRN_TABLE_HASH_KEY :
4157  case GRN_TABLE_NO_KEY :
4158  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4159  break;
4160  default :
4161  /* lookup failed */
4162  grn_obj_close(ctx, (grn_obj *)res);
4163  res = NULL;
4164  goto exit;
4165  }
4166  }
4167  }
4168  break;
4169  case 'v' : /* value */
4170  if (len != 6 || memcmp(name, "_value", 6)) { goto exit; }
4171  for (rp = &res; !done; rp = &(*rp)->next) {
4172  *rp = accessor_new(ctx);
4173  (*rp)->obj = obj;
4174  if (!obj->header.domain) {
4175  if (DB_OBJ((*rp)->obj)->range) {
4176  (*rp)->action = GRN_ACCESSOR_GET_VALUE;
4177  done++;
4178  } else {
4179  grn_obj_close(ctx, (grn_obj *)res);
4180  res = NULL;
4181  goto exit;
4182  }
4183  done++;
4184  } else {
4185  if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
4186  grn_obj_close(ctx, (grn_obj *)res);
4187  res = NULL;
4188  goto exit;
4189  }
4190  switch (obj->header.type) {
4191  case GRN_DB :
4192  case GRN_TYPE :
4193  if (DB_OBJ((*rp)->obj)->range) {
4194  (*rp)->action = GRN_ACCESSOR_GET_VALUE;
4195  done++;
4196  } else {
4197  grn_obj_close(ctx, (grn_obj *)res);
4198  res = NULL;
4199  goto exit;
4200  }
4201  break;
4202  case GRN_TABLE_PAT_KEY :
4203  case GRN_TABLE_DAT_KEY :
4204  case GRN_TABLE_HASH_KEY :
4205  case GRN_TABLE_NO_KEY :
4206  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4207  break;
4208  default :
4209  /* lookup failed */
4210  grn_obj_close(ctx, (grn_obj *)res);
4211  res = NULL;
4212  goto exit;
4213  }
4214  }
4215  }
4216  break;
4217  case 's' : /* score */
4218  if (len != 6 || memcmp(name, "_score", 6)) { goto exit; }
4219  for (rp = &res; !done; rp = &(*rp)->next) {
4220  *rp = accessor_new(ctx);
4221  (*rp)->obj = obj;
4222  if (DB_OBJ(obj)->header.flags & GRN_OBJ_WITH_SUBREC) {
4223  (*rp)->action = GRN_ACCESSOR_GET_SCORE;
4224  done++;
4225  } else {
4226  switch (obj->header.type) {
4227  case GRN_TABLE_PAT_KEY :
4228  case GRN_TABLE_DAT_KEY :
4229  case GRN_TABLE_HASH_KEY :
4230  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4231  break;
4232  case GRN_TABLE_NO_KEY :
4233  if (obj->header.domain) {
4234  (*rp)->action = GRN_ACCESSOR_GET_VALUE;
4235  break;
4236  }
4237  /* fallthru */
4238  default :
4239  /* lookup failed */
4240  grn_obj_close(ctx, (grn_obj *)res);
4241  res = NULL;
4242  goto exit;
4243  }
4244  if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
4245  grn_obj_close(ctx, (grn_obj *)res);
4246  res = NULL;
4247  goto exit;
4248  }
4249  }
4250  }
4251  break;
4252  case 'n' : /* nsubrecs */
4253  if (len != 9 || memcmp(name, "_nsubrecs", 9)) { goto exit; }
4254  for (rp = &res; !done; rp = &(*rp)->next) {
4255  *rp = accessor_new(ctx);
4256  (*rp)->obj = obj;
4257  if (GRN_TABLE_IS_GROUPED(obj)) {
4258  (*rp)->action = GRN_ACCESSOR_GET_NSUBRECS;
4259  done++;
4260  } else {
4261  switch (obj->header.type) {
4262  case GRN_TABLE_PAT_KEY :
4263  case GRN_TABLE_DAT_KEY :
4264  case GRN_TABLE_HASH_KEY :
4265  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4266  break;
4267  case GRN_TABLE_NO_KEY :
4268  if (obj->header.domain) {
4269  (*rp)->action = GRN_ACCESSOR_GET_VALUE;
4270  break;
4271  }
4272  /* fallthru */
4273  default :
4274  /* lookup failed */
4275  grn_obj_close(ctx, (grn_obj *)res);
4276  res = NULL;
4277  goto exit;
4278  }
4279  if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
4280  grn_obj_close(ctx, (grn_obj *)res);
4281  res = NULL;
4282  goto exit;
4283  }
4284  }
4285  }
4286  break;
4287  default :
4288  res = NULL;
4289  goto exit;
4290  }
4291  } else {
4292  /* if obj->header.type == GRN_TYPE ... lookup table */
4293  for (rp = &res; ; rp = &(*rp)->next) {
4294  grn_obj *column = grn_obj_column_(ctx, obj, name, len);
4295  if (column) {
4296  *rp = accessor_new(ctx);
4297  (*rp)->obj = column;
4298  /*
4299  switch (column->header.type) {
4300  case GRN_COLUMN_VAR_SIZE :
4301  break;
4302  case GRN_COLUMN_FIX_SIZE :
4303  break;
4304  case GRN_COLUMN_INDEX :
4305  break;
4306  }
4307  */
4308  (*rp)->action = GRN_ACCESSOR_GET_COLUMN_VALUE;
4309  break;
4310  } else {
4311  if (!obj->header.domain) {
4312  // ERR(GRN_INVALID_ARGUMENT, "no such column: <%s>", name);
4313  if (!is_chained) {
4314  grn_obj_close(ctx, (grn_obj *)res);
4315  }
4316  res = NULL;
4317  goto exit;
4318  }
4319  *rp = accessor_new(ctx);
4320  (*rp)->obj = obj;
4321  if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
4322  grn_obj_close(ctx, (grn_obj *)res);
4323  res = NULL;
4324  goto exit;
4325  }
4326  switch (obj->header.type) {
4327  case GRN_TABLE_PAT_KEY :
4328  case GRN_TABLE_DAT_KEY :
4329  case GRN_TABLE_HASH_KEY :
4330  case GRN_TABLE_NO_KEY :
4331  (*rp)->action = GRN_ACCESSOR_GET_KEY;
4332  break;
4333  default :
4334  /* lookup failed */
4335  grn_obj_close(ctx, (grn_obj *)res);
4336  res = NULL;
4337  goto exit;
4338  }
4339  }
4340  }
4341  }
4342  if (sp != se) {
4343  if (!grn_obj_get_accessor(ctx, (grn_obj *)res, sp, se - sp)) {
4344  if (!is_chained) {
4345  grn_obj_close(ctx, (grn_obj *)res);
4346  res = NULL;
4347  goto exit;
4348  }
4349  }
4350  }
4351  }
4352  if (rp0) { *rp0 = res; }
4353  exit :
4354  GRN_API_RETURN((grn_obj *)res);
4355 }
4356 
4357 inline static grn_bool
4358 grn_column_is_vector(grn_ctx *ctx, grn_obj *column)
4359 {
4361 
4362  if (column->header.type != GRN_COLUMN_VAR_SIZE) {
4363  return GRN_FALSE;
4364  }
4365 
4366  type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
4367  return type == GRN_OBJ_COLUMN_VECTOR;
4368 }
4369 
4370 inline static void
4371 grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj,
4372  grn_id *range_id, grn_obj_flags *range_flags)
4373 {
4374  if (GRN_DB_OBJP(obj)) {
4375  *range_id = DB_OBJ(obj)->range;
4376  if (grn_column_is_vector(ctx, obj)) {
4377  *range_flags = GRN_OBJ_VECTOR;
4378  }
4379  } else if (obj->header.type == GRN_ACCESSOR) {
4380  grn_accessor *a;
4381  for (a = (grn_accessor *)obj; a; a = a->next) {
4382  switch (a->action) {
4383  case GRN_ACCESSOR_GET_ID :
4384  *range_id = GRN_DB_UINT32;
4385  break;
4386  case GRN_ACCESSOR_GET_VALUE :
4387  if (GRN_DB_OBJP(a->obj)) {
4388  *range_id = DB_OBJ(a->obj)->range;
4389  }
4390  break;
4391  case GRN_ACCESSOR_GET_SCORE :
4393  *range_id = GRN_DB_INT32;
4394  break;
4396  if (GRN_DB_OBJP(a->obj)) {
4397  *range_id = DB_OBJ(a->obj)->range;
4398  if (grn_column_is_vector(ctx, a->obj)) {
4399  *range_flags = GRN_OBJ_VECTOR;
4400  }
4401  }
4402  break;
4403  case GRN_ACCESSOR_GET_KEY :
4404  if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->header.domain; }
4405  break;
4406  default :
4407  if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->range; }
4408  break;
4409  }
4410  }
4411  }
4412 }
4413 
4414 grn_id
4416 {
4417  grn_id range_id = GRN_ID_NIL;
4418  grn_obj_flags range_flags = 0;
4419 
4420  grn_obj_get_range_info(ctx, obj, &range_id, &range_flags);
4421 
4422  return range_id;
4423 }
4424 
4425 int
4427 {
4428  int res = 0;
4429  if (GRN_DB_OBJP(obj)) {
4430  res = IS_TEMP(obj) ? 0 : 1;
4431  } else if (obj->header.type == GRN_ACCESSOR) {
4432  grn_accessor *a;
4433  for (a = (grn_accessor *)obj; a; a = a->next) {
4434  switch (a->action) {
4435  case GRN_ACCESSOR_GET_SCORE :
4437  res = 0;
4438  break;
4439  case GRN_ACCESSOR_GET_ID :
4440  case GRN_ACCESSOR_GET_VALUE :
4442  case GRN_ACCESSOR_GET_KEY :
4443  if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
4444  break;
4445  default :
4446  if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
4447  break;
4448  }
4449  }
4450  }
4451  return res;
4452 }
4453 
4454 #define SRC2RECORD() do {\
4455  grn_obj *table = grn_ctx_at(ctx, dest->header.domain);\
4456  if (GRN_OBJ_TABLEP(table)) {\
4457  grn_obj *p_key = src;\
4458  grn_id id;\
4459  if (table->header.type != GRN_TABLE_NO_KEY) {\
4460  grn_obj key;\
4461  GRN_OBJ_INIT(&key, GRN_BULK, 0, table->header.domain);\
4462  if (src->header.domain != table->header.domain) {\
4463  grn_obj_cast(ctx, src, &key, GRN_TRUE);\
4464  p_key = &key;\
4465  }\
4466  if (GRN_BULK_VSIZE(p_key)) {\
4467  id = addp ? grn_table_add_by_key(ctx, table, p_key, NULL)\
4468  : grn_table_get_by_key(ctx, table, p_key);\
4469  if (id) { GRN_RECORD_SET(ctx, dest, id); }\
4470  } else {\
4471  GRN_RECORD_SET(ctx, dest, GRN_ID_NIL);\
4472  }\
4473  GRN_OBJ_FIN(ctx, &key);\
4474  } else {\
4475  grn_obj record_id;\
4476  GRN_UINT32_INIT(&record_id, 0);\
4477  grn_obj_cast(ctx, src, &record_id, GRN_TRUE);\
4478  id = GRN_UINT32_VALUE(&record_id);\
4479  if (id) { GRN_RECORD_SET(ctx, dest, id); }\
4480  }\
4481  } else {\
4482  rc = GRN_FUNCTION_NOT_IMPLEMENTED;\
4483  }\
4484 } while (0)
4485 
4486 inline static grn_rc
4487 grn_obj_cast_bool(grn_ctx *ctx, grn_obj *src, grn_obj *dest, grn_bool addp)
4488 {
4489  grn_rc rc = GRN_SUCCESS;
4490 
4491  switch (dest->header.domain) {
4492  case GRN_DB_BOOL :
4493  GRN_BOOL_SET(ctx, dest, GRN_BOOL_VALUE(src));
4494  break;
4495  case GRN_DB_INT8 :
4496  GRN_INT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
4497  break;
4498  case GRN_DB_UINT8 :
4499  GRN_UINT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
4500  break;
4501  case GRN_DB_INT16 :
4502  GRN_INT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
4503  break;
4504  case GRN_DB_UINT16 :
4505  GRN_UINT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
4506  break;
4507  case GRN_DB_INT32 :
4508  GRN_INT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
4509  break;
4510  case GRN_DB_UINT32 :
4511  GRN_UINT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
4512  break;
4513  case GRN_DB_INT64 :
4514  GRN_INT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
4515  break;
4516  case GRN_DB_UINT64 :
4517  GRN_UINT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
4518  break;
4519  case GRN_DB_FLOAT :
4520  GRN_FLOAT_SET(ctx, dest, GRN_BOOL_VALUE(src));
4521  break;
4522  case GRN_DB_TIME :
4523  GRN_TIME_SET(ctx, dest, GRN_BOOL_VALUE(src));
4524  break;
4525  case GRN_DB_SHORT_TEXT :
4526  case GRN_DB_TEXT :
4527  case GRN_DB_LONG_TEXT :
4528  {
4529  const char *bool_text;
4530  bool_text = GRN_BOOL_VALUE(src) ? "true" : "false";
4531  GRN_TEXT_PUTS(ctx, dest, bool_text);
4532  }
4533  break;
4534  case GRN_DB_TOKYO_GEO_POINT :
4535  case GRN_DB_WGS84_GEO_POINT :
4536  rc = GRN_INVALID_ARGUMENT;
4537  break;
4538  default :
4539  SRC2RECORD();
4540  break;
4541  }
4542  return rc;
4543 }
4544 
4545 #define NUM2DEST(getvalue,totext,tobool,totime,tofloat)\
4546  switch (dest->header.domain) {\
4547  case GRN_DB_BOOL :\
4548  tobool(ctx, dest, getvalue(src));\
4549  break;\
4550  case GRN_DB_INT8 :\
4551  GRN_INT8_SET(ctx, dest, getvalue(src));\
4552  break;\
4553  case GRN_DB_UINT8 :\
4554  GRN_UINT8_SET(ctx, dest, getvalue(src));\
4555  break;\
4556  case GRN_DB_INT16 :\
4557  GRN_INT16_SET(ctx, dest, getvalue(src));\
4558  break;\
4559  case GRN_DB_UINT16 :\
4560  GRN_UINT16_SET(ctx, dest, getvalue(src));\
4561  break;\
4562  case GRN_DB_INT32 :\
4563  GRN_INT32_SET(ctx, dest, getvalue(src));\
4564  break;\
4565  case GRN_DB_UINT32 :\
4566  GRN_UINT32_SET(ctx, dest, getvalue(src));\
4567  break;\
4568  case GRN_DB_TIME :\
4569  totime(ctx, dest, getvalue(src));\
4570  break;\
4571  case GRN_DB_INT64 :\
4572  GRN_INT64_SET(ctx, dest, getvalue(src));\
4573  break;\
4574  case GRN_DB_UINT64 :\
4575  GRN_UINT64_SET(ctx, dest, getvalue(src));\
4576  break;\
4577  case GRN_DB_FLOAT :\
4578  tofloat(ctx, dest, getvalue(src));\
4579  break;\
4580  case GRN_DB_SHORT_TEXT :\
4581  case GRN_DB_TEXT :\
4582  case GRN_DB_LONG_TEXT :\
4583  totext(ctx, dest, getvalue(src));\
4584  break;\
4585  case GRN_DB_TOKYO_GEO_POINT :\
4586  case GRN_DB_WGS84_GEO_POINT :\
4587  rc = GRN_INVALID_ARGUMENT;\
4588  break;\
4589  default :\
4590  SRC2RECORD();\
4591  break;\
4592  }
4593 
4594 #define TEXT2DEST(type,tonum,setvalue) do {\
4595  const char *cur, *str = GRN_TEXT_VALUE(src);\
4596  const char *str_end = GRN_BULK_CURR(src);\
4597  type i = tonum(str, str_end, &cur);\
4598  if (cur == str_end) {\
4599  setvalue(ctx, dest, i);\
4600  } else if (cur != str) {\
4601  const char *rest;\
4602  grn_obj buf;\
4603  GRN_VOID_INIT(&buf);\
4604  rc = grn_aton(ctx, str, str_end, &rest, &buf);\
4605  if (!rc) {\
4606  rc = grn_obj_cast(ctx, &buf, dest, addp);\
4607  }\
4608  GRN_OBJ_FIN(ctx, &buf);\
4609  } else {\
4610  rc = GRN_INVALID_ARGUMENT;\
4611  }\
4612 } while (0)
4613 
4614 #define NUM2BOOL(ctx, dest, value) GRN_BOOL_SET(ctx, dest, value != 0)
4615 #define FLOAT2BOOL(ctx, dest, value) do {\
4616  double value_ = value;\
4617  GRN_BOOL_SET(ctx, dest, value_ < -DBL_EPSILON || DBL_EPSILON < value_);\
4618 } while (0)
4619 
4620 #define NUM2TIME(ctx, dest, value)\
4621  GRN_TIME_SET(ctx, dest, (long long int)(value) * GRN_TIME_USEC_PER_SEC);
4622 #define TIME2TIME(ctx, dest, value)\
4623  GRN_TIME_SET(ctx, dest, value);
4624 #define FLOAT2TIME(ctx, dest, value)\
4625  GRN_TIME_SET(ctx, dest, (long long int)(value * GRN_TIME_USEC_PER_SEC));
4626 
4627 #define NUM2FLOAT(ctx, dest, value)\
4628  GRN_FLOAT_SET(ctx, dest, value);
4629 #define TIME2FLOAT(ctx, dest, value)\
4630  GRN_FLOAT_SET(ctx, dest, (double)(value) / GRN_TIME_USEC_PER_SEC);
4631 #define FLOAT2FLOAT(ctx, dest, value)\
4632  GRN_FLOAT_SET(ctx, dest, value);
4633 
4634 grn_rc
4635 grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, grn_bool addp)
4636 {
4637  grn_rc rc = GRN_SUCCESS;
4638  switch (src->header.domain) {
4639  case GRN_DB_BOOL :
4640  rc = grn_obj_cast_bool(ctx, src, dest, addp);
4641  break;
4642  case GRN_DB_INT8 :
4644  break;
4645  case GRN_DB_UINT8 :
4647  break;
4648  case GRN_DB_INT16 :
4650  break;
4651  case GRN_DB_UINT16 :
4653  break;
4654  case GRN_DB_INT32 :
4656  break;
4657  case GRN_DB_UINT32 :
4659  break;
4660  case GRN_DB_INT64 :
4662  break;
4663  case GRN_DB_TIME :
4665  break;
4666  case GRN_DB_UINT64 :
4668  break;
4669  case GRN_DB_FLOAT :
4671  FLOAT2FLOAT);
4672  break;
4673  case GRN_DB_SHORT_TEXT :
4674  case GRN_DB_TEXT :
4675  case GRN_DB_LONG_TEXT :
4676  switch (dest->header.domain) {
4677  case GRN_DB_BOOL :
4678  GRN_BOOL_SET(ctx, dest, GRN_TEXT_LEN(src) > 0);
4679  break;
4680  case GRN_DB_INT8 :
4681  TEXT2DEST(int8_t, grn_atoi8, GRN_INT8_SET);
4682  break;
4683  case GRN_DB_UINT8 :
4684  TEXT2DEST(uint8_t, grn_atoui8, GRN_UINT8_SET);
4685  break;
4686  case GRN_DB_INT16 :
4687  TEXT2DEST(int16_t, grn_atoi16, GRN_INT16_SET);
4688  break;
4689  case GRN_DB_UINT16 :
4690  TEXT2DEST(uint16_t, grn_atoui16, GRN_UINT16_SET);
4691  break;
4692  case GRN_DB_INT32 :
4693  TEXT2DEST(int32_t, grn_atoi, GRN_INT32_SET);
4694  break;
4695  case GRN_DB_UINT32 :
4696  TEXT2DEST(uint32_t, grn_atoui, GRN_UINT32_SET);
4697  break;
4698  case GRN_DB_TIME :
4699  {
4700  grn_timeval v;
4701  int len = GRN_TEXT_LEN(src);
4702  char *str = GRN_TEXT_VALUE(src);
4703  if (grn_str2timeval(str, len, &v)) {
4704  double d;
4705  char *end;
4706  grn_obj buf;
4707  GRN_TEXT_INIT(&buf, 0);
4708  GRN_TEXT_PUT(ctx, &buf, str, len);
4709  GRN_TEXT_PUTC(ctx, &buf, '\0');
4710  errno = 0;
4711  d = strtod(GRN_TEXT_VALUE(&buf), &end);
4712  if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
4713  v.tv_sec = d;
4714  v.tv_nsec = ((d - v.tv_sec) * GRN_TIME_NSEC_PER_SEC);
4715  } else {
4716  rc = GRN_INVALID_ARGUMENT;
4717  }
4718  GRN_OBJ_FIN(ctx, &buf);
4719  }
4720  GRN_TIME_SET(ctx, dest,
4721  GRN_TIME_PACK((int64_t)v.tv_sec,
4723  }
4724  break;
4725  case GRN_DB_INT64 :
4726  TEXT2DEST(int64_t, grn_atoll, GRN_INT64_SET);
4727  break;
4728  case GRN_DB_UINT64 :
4729  TEXT2DEST(int64_t, grn_atoll, GRN_UINT64_SET);
4730  break;
4731  case GRN_DB_FLOAT :
4732  {
4733  double d;
4734  char *end;
4735  grn_obj buf;
4736  GRN_TEXT_INIT(&buf, 0);
4737  GRN_TEXT_PUT(ctx, &buf, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
4738  GRN_TEXT_PUTC(ctx, &buf, '\0');
4739  errno = 0;
4740  d = strtod(GRN_TEXT_VALUE(&buf), &end);
4741  if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
4742  GRN_FLOAT_SET(ctx, dest, d);
4743  } else {
4744  rc = GRN_INVALID_ARGUMENT;
4745  }
4746  GRN_OBJ_FIN(ctx, &buf);
4747  }
4748  break;
4749  case GRN_DB_SHORT_TEXT :
4750  case GRN_DB_TEXT :
4751  case GRN_DB_LONG_TEXT :
4752  GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
4753  break;
4754  case GRN_DB_TOKYO_GEO_POINT :
4755  case GRN_DB_WGS84_GEO_POINT :
4756  {
4757  int latitude, longitude;
4758  double degree;
4759  const char *cur, *str = GRN_TEXT_VALUE(src);
4760  const char *str_end = GRN_BULK_CURR(src);
4761  if (str == str_end) {
4762  GRN_GEO_POINT_SET(ctx, dest, 0, 0);
4763  } else {
4764  char *end;
4765  grn_obj buf, *buf_p = NULL;
4766  latitude = grn_atoi(str, str_end, &cur);
4767  if (cur < str_end && cur[0] == '.') {
4768  GRN_TEXT_INIT(&buf, 0);
4769  GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
4770  GRN_TEXT_PUTC(ctx, &buf, '\0');
4771  buf_p = &buf;
4772  errno = 0;
4773  degree = strtod(GRN_TEXT_VALUE(buf_p), &end);
4774  if (errno) {
4775  rc = GRN_INVALID_ARGUMENT;
4776  } else {
4777  latitude = GRN_GEO_DEGREE2MSEC(degree);
4778  cur = str + (end - GRN_TEXT_VALUE(buf_p));
4779  }
4780  }
4781  if (!rc && (cur[0] == 'x' || cur[0] == ',') && cur + 1 < str_end) {
4782  const char *c = cur + 1;
4783  longitude = grn_atoi(c, str_end, &cur);
4784  if (cur < str_end && cur[0] == '.') {
4785  if (!buf_p) {
4786  GRN_TEXT_INIT(&buf, 0);
4787  GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
4788  GRN_TEXT_PUTC(ctx, &buf, '\0');
4789  buf_p = &buf;
4790  }
4791  errno = 0;
4792  degree = strtod(GRN_TEXT_VALUE(buf_p) + (c - str), &end);
4793  if (errno) {
4794  rc = GRN_INVALID_ARGUMENT;
4795  } else {
4796  longitude = GRN_GEO_DEGREE2MSEC(degree);
4797  cur = str + (end - GRN_TEXT_VALUE(buf_p));
4798  }
4799  }
4800  if (!rc && cur == str_end) {
4801  if ((-GRN_GEO_MAX_LATITUDE <= latitude &&
4802  latitude <= GRN_GEO_MAX_LATITUDE) &&
4803  (-GRN_GEO_MAX_LONGITUDE <= longitude &&
4804  longitude <= GRN_GEO_MAX_LONGITUDE)) {
4805  GRN_GEO_POINT_SET(ctx, dest, latitude, longitude);
4806  } else {
4807  rc = GRN_INVALID_ARGUMENT;
4808  }
4809  } else {
4810  rc = GRN_INVALID_ARGUMENT;
4811  }
4812  } else {
4813  rc = GRN_INVALID_ARGUMENT;
4814  }
4815  if (buf_p) { GRN_OBJ_FIN(ctx, buf_p); }
4816  }
4817  }
4818  break;
4819  default :
4820  SRC2RECORD();
4821  break;
4822  }
4823  break;
4824  case GRN_DB_TOKYO_GEO_POINT :
4825  case GRN_DB_WGS84_GEO_POINT :
4826  if (src->header.domain == dest->header.domain) {
4827  GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
4828  } else {
4829  int latitude, longitude;
4830  double latitude_in_degree, longitude_in_degree;
4831  GRN_GEO_POINT_VALUE(src, latitude, longitude);
4832  latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
4833  longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
4834  /* TokyoGeoPoint <-> WGS84GeoPoint is based on
4835  http://www.jalan.net/jw/jwp0200/jww0203.do
4836 
4837  jx: longitude in degree in Tokyo Geodetic System.
4838  jy: latitude in degree in Tokyo Geodetic System.
4839  wx: longitude in degree in WGS 84.
4840  wy: latitude in degree in WGS 84.
4841 
4842  jy = wy * 1.000106961 - wx * 0.000017467 - 0.004602017
4843  jx = wx * 1.000083049 + wy * 0.000046047 - 0.010041046
4844 
4845  wy = jy - jy * 0.00010695 + jx * 0.000017464 + 0.0046017
4846  wx = jx - jy * 0.000046038 - jx * 0.000083043 + 0.010040
4847  */
4848  if (dest->header.domain == GRN_DB_TOKYO_GEO_POINT) {
4849  double wgs84_latitude_in_degree = latitude_in_degree;
4850  double wgs84_longitude_in_degree = longitude_in_degree;
4851  int tokyo_latitude, tokyo_longitude;
4852  double tokyo_latitude_in_degree, tokyo_longitude_in_degree;
4853  tokyo_latitude_in_degree =
4854  wgs84_latitude_in_degree * 1.000106961 -
4855  wgs84_longitude_in_degree * 0.000017467 -
4856  0.004602017;
4857  tokyo_longitude_in_degree =
4858  wgs84_longitude_in_degree * 1.000083049 +
4859  wgs84_latitude_in_degree * 0.000046047 -
4860  0.010041046;
4861  tokyo_latitude = GRN_GEO_DEGREE2MSEC(tokyo_latitude_in_degree);
4862  tokyo_longitude = GRN_GEO_DEGREE2MSEC(tokyo_longitude_in_degree);
4863  GRN_GEO_POINT_SET(ctx, dest, tokyo_latitude, tokyo_longitude);
4864  } else {
4865  double tokyo_latitude_in_degree = latitude_in_degree;
4866  double tokyo_longitude_in_degree = longitude_in_degree;
4867  int wgs84_latitude, wgs84_longitude;
4868  double wgs84_latitude_in_degree, wgs84_longitude_in_degree;
4869  wgs84_latitude_in_degree =
4870  tokyo_latitude_in_degree -
4871  tokyo_latitude_in_degree * 0.00010695 +
4872  tokyo_longitude_in_degree * 0.000017464 +
4873  0.0046017;
4874  wgs84_longitude_in_degree =
4875  tokyo_longitude_in_degree -
4876  tokyo_latitude_in_degree * 0.000046038 -
4877  tokyo_longitude_in_degree * 0.000083043 +
4878  0.010040;
4879  wgs84_latitude = GRN_GEO_DEGREE2MSEC(wgs84_latitude_in_degree);
4880  wgs84_longitude = GRN_GEO_DEGREE2MSEC(wgs84_longitude_in_degree);
4881  GRN_GEO_POINT_SET(ctx, dest, wgs84_latitude, wgs84_longitude);
4882  }
4883  }
4884  break;
4885  case GRN_VOID :
4886  rc = grn_obj_reinit(ctx, dest, dest->header.domain, dest->header.flags);
4887  break;
4888  default :
4890  break;
4891  }
4892  return rc;
4893 }
4894 
4895 const char *
4897 {
4898  const char *value = NULL;
4899  for (;;) {
4900  switch (a->action) {
4901  case GRN_ACCESSOR_GET_ID :
4902  value = (const char *)(uintptr_t)id;
4903  *size = GRN_OBJ_GET_VALUE_IMD;
4904  break;
4905  case GRN_ACCESSOR_GET_KEY :
4906  value = _grn_table_key(ctx, a->obj, id, size);
4907  break;
4908  case GRN_ACCESSOR_GET_VALUE :
4909  value = grn_obj_get_value_(ctx, a->obj, id, size);
4910  break;
4911  case GRN_ACCESSOR_GET_SCORE :
4912  if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
4913  value = (const char *)&((grn_rset_recinfo *)value)->score;
4914  *size = sizeof(int);
4915  }
4916  break;
4918  if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
4919  value = (const char *)&((grn_rset_recinfo *)value)->n_subrecs;
4920  *size = sizeof(int);
4921  }
4922  break;
4924  /* todo : support vector */
4925  value = grn_obj_get_value_(ctx, a->obj, id, size);
4926  break;
4928  value = _grn_table_key(ctx, ((grn_db *)ctx->impl->db)->keys, id, size);
4929  break;
4930  case GRN_ACCESSOR_LOOKUP :
4931  /* todo */
4932  break;
4933  case GRN_ACCESSOR_FUNCALL :
4934  /* todo */
4935  break;
4936  }
4937  if (value && (a = a->next)) {
4938  id = *((grn_id *)value);
4939  } else {
4940  break;
4941  }
4942  }
4943  return value;
4944 }
4945 
4946 static grn_obj *
4947 grn_accessor_get_value(grn_ctx *ctx, grn_accessor *a, grn_id id, grn_obj *value)
4948 {
4949  uint32_t vs = 0;
4950  uint32_t size0;
4951  void *vp = NULL;
4952  if (!value) {
4953  if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) { return NULL; }
4954  } else {
4955  value->header.type = GRN_BULK;
4956  }
4957  size0 = GRN_BULK_VSIZE(value);
4958  for (;;) {
4959  grn_bulk_truncate(ctx, value, size0);
4960  switch (a->action) {
4961  case GRN_ACCESSOR_GET_ID :
4962  GRN_UINT32_PUT(ctx, value, id);
4963  vp = GRN_BULK_HEAD(value) + size0;
4964  vs = GRN_BULK_VSIZE(value) - size0;
4965  break;
4966  case GRN_ACCESSOR_GET_KEY :
4967  grn_table_get_key2(ctx, a->obj, id, value);
4968  vp = GRN_BULK_HEAD(value) + size0;
4969  vs = GRN_BULK_VSIZE(value) - size0;
4970  break;
4971  case GRN_ACCESSOR_GET_VALUE :
4972  grn_obj_get_value(ctx, a->obj, id, value);
4973  vp = GRN_BULK_HEAD(value) + size0;
4974  vs = GRN_BULK_VSIZE(value) - size0;
4975  break;
4976  case GRN_ACCESSOR_GET_SCORE :
4977  grn_obj_get_value(ctx, a->obj, id, value);
4978  {
4979  grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
4980  GRN_INT32_PUT(ctx, value, ri->score);
4981  }
4982  break;
4984  {
4985  grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
4986  GRN_INT32_PUT(ctx, value, ri->n_subrecs);
4987  }
4988  break;
4990  /* todo : support vector */
4991  grn_obj_get_value(ctx, a->obj, id, value);
4992  vp = GRN_BULK_HEAD(value) + size0;
4993  vs = GRN_BULK_VSIZE(value) - size0;
4994  break;
4996  value = grn_ctx_at(ctx, id);
4997  grn_obj_close(ctx, value);
4998  return value;
4999  break;
5000  case GRN_ACCESSOR_LOOKUP :
5001  /* todo */
5002  break;
5003  case GRN_ACCESSOR_FUNCALL :
5004  /* todo */
5005  break;
5006  }
5007  if ((a = a->next)) {
5008  id = *((grn_id *)vp);
5009  } else {
5010  break;
5011  }
5012  }
5013  return value;
5014 }
5015 
5016 static grn_rc
5017 grn_accessor_set_value(grn_ctx *ctx, grn_accessor *a, grn_id id,
5018  grn_obj *value, int flags)
5019 {
5020  grn_rc rc = GRN_SUCCESS;
5021  if (!value) { value = grn_obj_open(ctx, GRN_BULK, 0, 0); }
5022  if (value) {
5023  grn_obj buf;
5024  void *vp = NULL;
5025  GRN_TEXT_INIT(&buf, 0);
5026  for (;;) {
5027  GRN_BULK_REWIND(&buf);
5028  switch (a->action) {
5029  case GRN_ACCESSOR_GET_KEY :
5030  grn_table_get_key2(ctx, a->obj, id, &buf);
5031  vp = GRN_BULK_HEAD(&buf);
5032  break;
5033  case GRN_ACCESSOR_GET_VALUE :
5034  if (a->next) {
5035  grn_obj_get_value(ctx, a->obj, id, &buf);
5036  vp = GRN_BULK_HEAD(&buf);
5037  } else {
5038  rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
5039  }
5040  break;
5041  case GRN_ACCESSOR_GET_SCORE :
5042  {
5043  grn_rset_recinfo *ri;
5044  if (a->next) {
5045  grn_obj_get_value(ctx, a->obj, id, &buf);
5046  ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
5047  vp = &ri->score;
5048  } else {
5049  uint32_t size;
5050  if ((ri = (grn_rset_recinfo *) grn_obj_get_value_(ctx, a->obj, id, &size))) {
5051  vp = &ri->score;
5052  // todo : flags support
5053  if (value->header.domain == GRN_DB_INT32) {
5054  memcpy(vp, GRN_BULK_HEAD(value), sizeof(int));
5055  } else {
5056  grn_obj buf;
5057  GRN_INT32_INIT(&buf, 0);
5058  grn_obj_cast(ctx, value, &buf, GRN_FALSE);
5059  memcpy(vp, GRN_BULK_HEAD(&buf), sizeof(int));
5060  GRN_OBJ_FIN(ctx, &buf);
5061  }
5062  }
5063  }
5064  }
5065  break;
5067  grn_obj_get_value(ctx, a->obj, id, &buf);
5068  {
5070  vp = &ri->n_subrecs;
5071  }
5072  break;
5074  /* todo : support vector */
5075  if (a->next) {
5076  grn_obj_get_value(ctx, a->obj, id, &buf);
5077  vp = GRN_BULK_HEAD(&buf);
5078  } else {
5079  rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
5080  }
5081  break;
5082  case GRN_ACCESSOR_LOOKUP :
5083  /* todo */
5084  break;
5085  case GRN_ACCESSOR_FUNCALL :
5086  /* todo */
5087  break;
5088  }
5089  if ((a = a->next)) {
5090  id = *((grn_id *)vp);
5091  } else {
5092  break;
5093  }
5094  }
5095  grn_obj_close(ctx, &buf);
5096  }
5097  return rc;
5098 }
5099 
5100 #define INCRDECR(op) \
5101  switch (DB_OBJ(obj)->range) {\
5102  case GRN_DB_INT8 :\
5103  if (s == sizeof(int8_t)) {\
5104  int8_t *vp = (int8_t *)p;\
5105  *vp op *(int8_t *)v;\
5106  rc = GRN_SUCCESS;\
5107  } else {\
5108  rc = GRN_INVALID_ARGUMENT;\
5109  }\
5110  break;\
5111  case GRN_DB_UINT8 :\
5112  if (s == sizeof(uint8_t)) {\
5113  uint8_t *vp = (uint8_t *)p;\
5114  *vp op *(int8_t *)v;\
5115  rc = GRN_SUCCESS;\
5116  } else {\
5117  rc = GRN_INVALID_ARGUMENT;\
5118  }\
5119  break;\
5120  case GRN_DB_INT16 :\
5121  if (s == sizeof(int16_t)) {\
5122  int16_t *vp = (int16_t *)p;\
5123  *vp op *(int16_t *)v;\
5124  rc = GRN_SUCCESS;\
5125  } else {\
5126  rc = GRN_INVALID_ARGUMENT;\
5127  }\
5128  break;\
5129  case GRN_DB_UINT16 :\
5130  if (s == sizeof(uint16_t)) {\
5131  uint16_t *vp = (uint16_t *)p;\
5132  *vp op *(int16_t *)v;\
5133  rc = GRN_SUCCESS;\
5134  } else {\
5135  rc = GRN_INVALID_ARGUMENT;\
5136  }\
5137  break;\
5138  case GRN_DB_INT32 :\
5139  if (s == sizeof(int32_t)) {\
5140  int32_t *vp = (int32_t *)p;\
5141  *vp op *(int32_t *)v;\
5142  rc = GRN_SUCCESS;\
5143  } else {\
5144  rc = GRN_INVALID_ARGUMENT;\
5145  }\
5146  break;\
5147  case GRN_DB_UINT32 :\
5148  if (s == sizeof(uint32_t)) {\
5149  uint32_t *vp = (uint32_t *)p;\
5150  *vp op *(int32_t *)v;\
5151  rc = GRN_SUCCESS;\
5152  } else {\
5153  rc = GRN_INVALID_ARGUMENT;\
5154  }\
5155  break;\
5156  case GRN_DB_INT64 :\
5157  case GRN_DB_TIME :\
5158  if (s == sizeof(int64_t)) {\
5159  int64_t *vp = (int64_t *)p;\
5160  *vp op *(int64_t *)v;\
5161  rc = GRN_SUCCESS;\
5162  } else {\
5163  rc = GRN_INVALID_ARGUMENT;\
5164  }\
5165  break;\
5166  case GRN_DB_FLOAT :\
5167  if (s == sizeof(double)) {\
5168  double *vp = (double *)p;\
5169  *vp op *(double *)v;\
5170  rc = GRN_SUCCESS;\
5171  } else {\
5172  rc = GRN_INVALID_ARGUMENT;\
5173  }\
5174  break;\
5175  default :\
5176  rc = GRN_OPERATION_NOT_SUPPORTED;\
5177  break;\
5178  }
5179 
5180 uint32_t
5182 {
5183  if (!obj) { return 0; }
5184  switch (obj->header.type) {
5185  case GRN_VOID :
5186  case GRN_BULK :
5187  case GRN_PTR :
5188  case GRN_UVECTOR :
5189  case GRN_PVECTOR :
5190  case GRN_MSG :
5191  return GRN_BULK_VSIZE(obj);
5192  case GRN_VECTOR :
5193  return obj->u.v.body ? GRN_BULK_VSIZE(obj->u.v.body) : 0;
5194  default :
5195  return 0;
5196  }
5197 }
5198 
5199 inline static int
5200 call_hook(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value, int flags)
5201 {
5202  grn_hook *hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET];
5203  void *v = GRN_BULK_HEAD(value);
5204  unsigned int s = grn_obj_size(ctx, value);
5205  if (hooks || obj->header.type == GRN_COLUMN_VAR_SIZE) {
5206  grn_obj oldbuf, *oldvalue;
5207  GRN_TEXT_INIT(&oldbuf, 0);
5208  oldvalue = grn_obj_get_value(ctx, obj, id, &oldbuf);
5209  if (flags & GRN_OBJ_SET) {
5210  void *ov;
5211  unsigned int os;
5212  ov = GRN_BULK_HEAD(oldvalue);
5213  os = grn_obj_size(ctx, oldvalue);
5214  if ((ov && v && os == s && !memcmp(ov, v, s)) &&
5215  !(obj->header.type == GRN_COLUMN_FIX_SIZE &&
5216  grn_bulk_is_zero(ctx, value))) {
5217  grn_obj_close(ctx, oldvalue);
5218  return 0;
5219  }
5220  }
5221  if (hooks) {
5222  // todo : grn_proc_ctx_open()
5223  grn_obj id_, flags_;
5224  grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
5225  GRN_UINT32_INIT(&id_, 0);
5226  GRN_UINT32_INIT(&flags_, 0);
5227  GRN_UINT32_SET(ctx, &id_, id);
5228  GRN_UINT32_SET(ctx, &flags_, flags);
5229  while (hooks) {
5230  grn_ctx_push(ctx, &id_);
5231  grn_ctx_push(ctx, oldvalue);
5232  grn_ctx_push(ctx, value);
5233  grn_ctx_push(ctx, &flags_);
5234  pctx.caller = NULL;
5235  pctx.currh = hooks;
5236  if (hooks->proc) {
5237  hooks->proc->funcs[PROC_INIT](ctx, 1, &obj, &pctx.user_data);
5238  } else {
5239  default_set_value_hook(ctx, 1, &obj, &pctx.user_data);
5240  }
5241  if (ctx->rc) {
5242  grn_obj_close(ctx, oldvalue);
5243  return 1;
5244  }
5245  hooks = hooks->next;
5246  pctx.offset++;
5247  }
5248  }
5249  grn_obj_close(ctx, oldvalue);
5250  }
5251  return 0;
5252 }
5253 
5254 inline static int
5255 call_hook_for_build(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value, int flags)
5256 {
5257  grn_hook *hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET];
5258 
5259  if (hooks || obj->header.type == GRN_COLUMN_VAR_SIZE) {
5260  grn_obj oldvalue;
5261  GRN_TEXT_INIT(&oldvalue, 0);
5262 
5263  if (hooks) {
5264  // todo : grn_proc_ctx_open()
5265  grn_obj id_, flags_;
5266  grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
5267  GRN_UINT32_INIT(&id_, 0);
5268  GRN_UINT32_INIT(&flags_, 0);
5269  GRN_UINT32_SET(ctx, &id_, id);
5270  GRN_UINT32_SET(ctx, &flags_, flags);
5271  while (hooks) {
5272  grn_ctx_push(ctx, &id_);
5273  grn_ctx_push(ctx, &oldvalue);
5274  grn_ctx_push(ctx, value);
5275  grn_ctx_push(ctx, &flags_);
5276  pctx.caller = NULL;
5277  pctx.currh = hooks;
5278  if (hooks->proc) {
5279  hooks->proc->funcs[PROC_INIT](ctx, 1, &obj, &pctx.user_data);
5280  } else {
5281  default_set_value_hook(ctx, 1, &obj, &pctx.user_data);
5282  }
5283  if (ctx->rc) {
5284  grn_obj_close(ctx, &oldvalue);
5285  return 1;
5286  }
5287  hooks = hooks->next;
5288  pctx.offset++;
5289  }
5290  }
5291  grn_obj_close(ctx, &oldvalue);
5292  }
5293  return 0;
5294 }
5295 
5296 static grn_rc
5297 grn_obj_set_value_table_pat_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
5298  grn_obj *value, int flags)
5299 {
5301  grn_id range = DB_OBJ(obj)->range;
5302  void *v = GRN_BULK_HEAD(value);
5303  grn_obj buf;
5304 
5305  if (call_hook(ctx, obj, id, value, flags)) {
5306  return rc;
5307  }
5308 
5309  if (range != value->header.domain) {
5310  GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
5311  if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
5312  v = GRN_BULK_HEAD(&buf);
5313  }
5314  }
5315  rc = grn_pat_set_value(ctx, (grn_pat *)obj, id, v, flags);
5316  if (range != value->header.domain) {
5317  grn_obj_close(ctx, &buf);
5318  }
5319 
5320  return rc;
5321 }
5322 
5323 static grn_rc
5324 grn_obj_set_value_table_hash_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
5325  grn_obj *value, int flags)
5326 {
5328  grn_id range = DB_OBJ(obj)->range;
5329  void *v = GRN_BULK_HEAD(value);
5330  grn_obj buf;
5331 
5332  if (call_hook(ctx, obj, id, value, flags)) {
5333  return rc;
5334  }
5335 
5336  if (range != value->header.domain) {
5337  GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
5338  if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
5339  v = GRN_BULK_HEAD(&buf);
5340  }
5341  }
5342  rc = grn_hash_set_value(ctx, (grn_hash *)obj, id, v, flags);
5343  if (range != value->header.domain) {
5344  grn_obj_close(ctx, &buf);
5345  }
5346 
5347  return rc;
5348 }
5349 
5350 static grn_rc
5351 grn_obj_set_value_table_no_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
5352  grn_obj *value, int flags)
5353 {
5355  grn_id range = DB_OBJ(obj)->range;
5356  void *v = GRN_BULK_HEAD(value);
5357  grn_obj buf;
5358 
5359  if (call_hook(ctx, obj, id, value, flags)) {
5360  return rc;
5361  }
5362 
5363  if (range != value->header.domain) {
5364  GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
5365  if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
5366  v = GRN_BULK_HEAD(&buf);
5367  }
5368  }
5369  rc = grn_array_set_value(ctx, (grn_array *)obj, id, v, flags);
5370  if (range != value->header.domain) {
5371  grn_obj_close(ctx, &buf);
5372  }
5373 
5374  return rc;
5375 }
5376 
5377 static grn_rc
5378 grn_obj_set_value_column_var_size_scalar(grn_ctx *ctx, grn_obj *obj, grn_id id,
5379  grn_obj *value, int flags)
5380 {
5382  grn_id range = DB_OBJ(obj)->range;
5383  void *v = GRN_BULK_HEAD(value);
5384  unsigned int s = grn_obj_size(ctx, value);
5385  grn_obj buf;
5386  grn_id buf_domain = GRN_DB_VOID;
5387 
5388  if (call_hook(ctx, obj, id, value, flags)) {
5389  return rc;
5390  }
5391 
5392  switch (flags & GRN_OBJ_SET_MASK) {
5393  case GRN_OBJ_INCR :
5394  case GRN_OBJ_DECR :
5395  if (value->header.domain == GRN_DB_INT32 ||
5396  value->header.domain == GRN_DB_INT64) {
5397  /* do nothing */
5398  } else if (GRN_DB_INT8 <= value->header.domain &&
5399  value->header.domain < GRN_DB_INT32) {
5400  buf_domain = GRN_DB_INT32;
5401  } else {
5402  buf_domain = GRN_DB_INT64;
5403  }
5404  break;
5405  default :
5406  if (range != value->header.domain) {
5407  buf_domain = range;
5408  }
5409  break;
5410  }
5411 
5412  if (buf_domain != GRN_DB_VOID) {
5413  GRN_OBJ_INIT(&buf, GRN_BULK, 0, buf_domain);
5414  if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
5415  v = GRN_BULK_HEAD(&buf);
5416  s = GRN_BULK_VSIZE(&buf);
5417  }
5418  }
5419 
5420  rc = grn_ja_put(ctx, (grn_ja *)obj, id, v, s, flags, NULL);
5421 
5422  if (buf_domain != GRN_DB_VOID) {
5423  grn_obj_close(ctx, &buf);
5424  }
5425 
5426  return rc;
5427 }
5428 
5429 static grn_rc
5430 grn_obj_set_value_column_var_size_vector(grn_ctx *ctx, grn_obj *obj, grn_id id,
5431  grn_obj *value, int flags)
5432 {
5434  grn_id range = DB_OBJ(obj)->range;
5435  void *v = GRN_BULK_HEAD(value);
5436  unsigned int s = grn_obj_size(ctx, value);
5437  grn_obj *lexicon = grn_ctx_at(ctx, range);
5438 
5439  if (call_hook(ctx, obj, id, value, flags)) {
5440  return rc;
5441  }
5442 
5443  if (GRN_OBJ_TABLEP(lexicon)) {
5444  grn_obj buf;
5445  GRN_TEXT_INIT(&buf, 0);
5446  switch (value->header.type) {
5447  case GRN_BULK :
5448  {
5449  unsigned int token_flags = 0;
5450  grn_token *token;
5451  if (v && s &&
5452  (token = grn_token_open(ctx, lexicon, v, s,
5453  GRN_TOKEN_ADD, token_flags))) {
5454  while (!token->status) {
5455  grn_id tid = grn_token_next(ctx, token);
5456  grn_bulk_write(ctx, &buf, (char *)&tid, sizeof(grn_id));
5457  }
5458  grn_token_close(ctx, token);
5459  }
5460  rc = grn_ja_put(ctx, (grn_ja *)obj, id,
5461  GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf), flags, NULL);
5462  }
5463  break;
5464  case GRN_VECTOR :
5465  if (value->u.v.body) {
5466  int j;
5467  grn_section *v;
5468  grn_obj value_buf, cast_buf;
5469  const char *head = GRN_BULK_HEAD(value->u.v.body);
5470  GRN_OBJ_INIT(&value_buf, GRN_BULK, 0, GRN_DB_VOID);
5471  GRN_OBJ_INIT(&cast_buf, GRN_BULK, 0, lexicon->header.domain);
5472  for (j = value->u.v.n_sections, v = value->u.v.sections; j; j--, v++) {
5473  const char *value_ptr = head + v->offset;
5474  int value_length = v->length;
5475  grn_id tid;
5476  if (v->domain != lexicon->header.domain) {
5477  GRN_BULK_REWIND(&cast_buf);
5478  GRN_BULK_REWIND(&value_buf);
5479  grn_bulk_write(ctx, &value_buf, value_ptr, value_length);
5480  value_buf.header.domain = v->domain;
5481  rc = grn_obj_cast(ctx, &value_buf, &cast_buf, GRN_TRUE);
5482  if (rc) {
5483  grn_obj *range_obj;
5484  range_obj = grn_ctx_at(ctx, range);
5485  REPORT_CAST_ERROR(obj, range_obj, &value_buf);
5486  grn_obj_unlink(ctx, range_obj);
5487  } else {
5488  value_ptr = GRN_BULK_HEAD(&cast_buf);
5489  value_length = GRN_BULK_VSIZE(&cast_buf);
5490  }
5491  } else {
5492  rc = GRN_SUCCESS;
5493  }
5494  if (rc) {
5495  continue;
5496  }
5497  tid = grn_table_add(ctx, lexicon,
5498  value_ptr, value_length, NULL);
5499  grn_bulk_write(ctx, &buf, (char *)&tid, sizeof(grn_id));
5500  }
5501  GRN_OBJ_FIN(ctx, &value_buf);
5502  GRN_OBJ_FIN(ctx, &cast_buf);
5503  }
5504  rc = grn_ja_put(ctx, (grn_ja *)obj, id,
5505  GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf), flags, NULL);
5506  break;
5507  case GRN_UVECTOR :
5508  rc = grn_ja_put(ctx, (grn_ja *)obj, id, v, s, flags, NULL);
5509  break;
5510  default :
5511  ERR(GRN_INVALID_ARGUMENT, "vector, uvector or bulk required");
5512  break;
5513  }
5514  grn_obj_close(ctx, &buf);
5515  } else {
5516  switch (value->header.type) {
5517  case GRN_BULK :
5518  if (!GRN_BULK_VSIZE(value)) {
5519  rc = grn_ja_put(ctx, (grn_ja *)obj, id, NULL, 0, flags, NULL);
5520  } else {
5521  grn_obj v;
5523  v.u.v.body = value;
5524  grn_vector_delimit(ctx, &v, 0, GRN_ID_NIL);
5525  rc = grn_ja_putv(ctx, (grn_ja *)obj, id, &v, 0);
5526  grn_obj_close(ctx, &v);
5527  }
5528  break;
5529  case GRN_UVECTOR :
5530  rc = grn_ja_put(ctx, (grn_ja *)obj, id, v, s, flags, NULL);
5531  break;
5532  case GRN_VECTOR :
5533  rc = grn_ja_putv(ctx, (grn_ja *)obj, id, value, 0);
5534  break;
5535  default :
5536  ERR(GRN_INVALID_ARGUMENT, "vector or bulk required");
5537  break;
5538  }
5539  }
5540  return rc;
5541 }
5542 
5543 static grn_rc
5544 grn_obj_set_value_column_fix_size(grn_ctx *ctx, grn_obj *obj, grn_id id,
5545  grn_obj *value, int flags)
5546 {
5548  grn_id range = DB_OBJ(obj)->range;
5549  void *v = GRN_BULK_HEAD(value);
5550  unsigned int s = grn_obj_size(ctx, value);
5551  grn_obj buf, *value_ = value;
5552  uint32_t element_size = ((grn_ra *)obj)->header->element_size;
5553  GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
5554  if (range != value->header.domain) {
5555  rc = grn_obj_cast(ctx, value, &buf, GRN_TRUE);
5556  if (rc) {
5557  grn_obj *range_obj;
5558  range_obj = grn_ctx_at(ctx, range);
5559  REPORT_CAST_ERROR(obj, range_obj, value);
5560  grn_obj_unlink(ctx, range_obj);
5561  } else {
5562  value_ = &buf;
5563  v = GRN_BULK_HEAD(&buf);
5564  s = GRN_BULK_VSIZE(&buf);
5565  }
5566  } else {
5567  rc = GRN_SUCCESS;
5568  }
5569  if (rc) {
5570  /* do nothing because it already has error. */
5571  } else if (element_size < s) {
5572  ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", s);
5573  } else {
5574  void *p = grn_ra_ref(ctx, (grn_ra *)obj, id);
5575  if (!p) {
5576  ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
5578  return rc;
5579  }
5580  switch (flags & GRN_OBJ_SET_MASK) {
5581  case GRN_OBJ_SET :
5582  if (call_hook(ctx, obj, id, value_, flags)) {
5583  GRN_OBJ_FIN(ctx, &buf);
5584  grn_ra_unref(ctx, (grn_ra *)obj, id);
5585  return rc;
5586  }
5587  if (element_size != s) {
5588  if (!s) {
5589  memset(p, 0, element_size);
5590  } else {
5591  void *b;
5592  if ((b = GRN_CALLOC(element_size))) {
5593  memcpy(b, v, s);
5594  memcpy(p, b, element_size);
5595  GRN_FREE(b);
5596  }
5597  }
5598  } else {
5599  memcpy(p, v, s);
5600  }
5601  rc = GRN_SUCCESS;
5602  break;
5603  case GRN_OBJ_INCR :
5604  /* todo : support hook */
5605  INCRDECR(+=);
5606  break;
5607  case GRN_OBJ_DECR :
5608  /* todo : support hook */
5609  INCRDECR(-=);
5610  break;
5611  default :
5613  break;
5614  }
5615  grn_ra_unref(ctx, (grn_ra *)obj, id);
5616  }
5617  GRN_OBJ_FIN(ctx, &buf);
5618  return rc;
5619 }
5620 
5621 grn_rc
5623  grn_obj *value, int flags)
5624 {
5626  GRN_API_ENTER;
5627  if (!GRN_DB_OBJP(obj)) {
5628  if (obj->header.type == GRN_ACCESSOR) {
5629  rc = grn_accessor_set_value(ctx, (grn_accessor *)obj, id, value, flags);
5630  } else {
5631  ERR(GRN_INVALID_ARGUMENT, "not db_obj");
5632  }
5633  } else {
5634  switch (obj->header.type) {
5635  case GRN_TABLE_PAT_KEY :
5636  rc = grn_obj_set_value_table_pat_key(ctx, obj, id, value, flags);
5637  break;
5638  case GRN_TABLE_DAT_KEY :
5640  break;
5641  case GRN_TABLE_HASH_KEY :
5642  rc = grn_obj_set_value_table_hash_key(ctx, obj, id, value, flags);
5643  break;
5644  case GRN_TABLE_NO_KEY :
5645  rc = grn_obj_set_value_table_no_key(ctx, obj, id, value, flags);
5646  break;
5647  case GRN_COLUMN_VAR_SIZE :
5648  switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
5649  case GRN_OBJ_COLUMN_SCALAR :
5650  rc = grn_obj_set_value_column_var_size_scalar(ctx, obj, id, value,
5651  flags);
5652  break;
5653  case GRN_OBJ_COLUMN_VECTOR :
5654  rc = grn_obj_set_value_column_var_size_vector(ctx, obj, id, value,
5655  flags);
5656  break;
5657  default :
5658  ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
5659  break;
5660  }
5661  break;
5662  case GRN_COLUMN_FIX_SIZE :
5663  rc = grn_obj_set_value_column_fix_size(ctx, obj, id, value, flags);
5664  break;
5665  case GRN_COLUMN_INDEX :
5666  // todo : how??
5667  break;
5668  }
5669  }
5670  GRN_API_RETURN(rc);
5671 }
5672 
5673 const char *
5674 grn_obj_get_value_(grn_ctx *ctx, grn_obj *obj, grn_id id, uint32_t *size)
5675 {
5676  const char *value = NULL;
5677  *size = 0;
5678  switch (obj->header.type) {
5679  case GRN_ACCESSOR :
5680  value = grn_accessor_get_value_(ctx, (grn_accessor *)obj, id, size);
5681  break;
5682  case GRN_TABLE_PAT_KEY :
5683  value = grn_pat_get_value_(ctx, (grn_pat *)obj, id, size);
5684  break;
5685  case GRN_TABLE_DAT_KEY :
5686  ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
5687  break;
5688  case GRN_TABLE_HASH_KEY :
5689  value = grn_hash_get_value_(ctx, (grn_hash *)obj, id, size);
5690  break;
5691  case GRN_TABLE_NO_KEY :
5692  if ((value = _grn_array_get_value(ctx, (grn_array *)obj, id))) {
5693  *size = ((grn_array *)obj)->value_size;
5694  }
5695  break;
5696  case GRN_COLUMN_VAR_SIZE :
5697  {
5698  grn_io_win jw;
5699  if ((value = grn_ja_ref(ctx, (grn_ja *)obj, id, &jw, size))) {
5700  grn_ja_unref(ctx, &jw);
5701  }
5702  }
5703  break;
5704  case GRN_COLUMN_FIX_SIZE :
5705  if ((value = grn_ra_ref(ctx, (grn_ra *)obj, id))) {
5706  grn_ra_unref(ctx, (grn_ra *)obj, id);
5707  *size = ((grn_ra *)obj)->header->element_size;
5708  }
5709  break;
5710  case GRN_COLUMN_INDEX :
5711  ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "todo: GRN_COLUMN_INDEX");
5712  break;
5713  }
5714  return value;
5715 }
5716 
5717 grn_obj *
5719 {
5720  GRN_API_ENTER;
5721  if (!id) { goto exit; }
5722  if (!obj) {
5723  ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
5724  goto exit;
5725  }
5726  if (!value) {
5727  if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
5728  ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
5729  goto exit;
5730  }
5731  }
5732  switch (value->header.type) {
5733  case GRN_VOID :
5734  GRN_TEXT_INIT(value, 0);
5735  break;
5736  case GRN_BULK :
5737  case GRN_VECTOR :
5738  case GRN_UVECTOR :
5739  case GRN_MSG :
5740  break;
5741  default :
5742  ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
5743  goto exit;
5744  }
5745  switch (obj->header.type) {
5746  case GRN_ACCESSOR :
5747  grn_obj_ensure_bulk(ctx, value);
5748  value = grn_accessor_get_value(ctx, (grn_accessor *)obj, id, value);
5749  value->header.domain = grn_obj_get_range(ctx, obj);
5750  break;
5751  case GRN_TABLE_PAT_KEY :
5752  {
5753  grn_pat *pat = (grn_pat *)obj;
5754  uint32_t size = pat->value_size;
5755  grn_obj_ensure_bulk(ctx, value);
5756  if (grn_bulk_space(ctx, value, size)) {
5757  MERR("grn_bulk_space failed");
5758  goto exit;
5759  }
5760  {
5761  char *curr = GRN_BULK_CURR(value);
5762  grn_pat_get_value(ctx, pat, id, curr - size);
5763  }
5764  value->header.type = GRN_BULK;
5765  value->header.domain = grn_obj_get_range(ctx, obj);
5766  }
5767  break;
5768  case GRN_TABLE_DAT_KEY :
5769  ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
5770  break;
5771  case GRN_TABLE_HASH_KEY :
5772  {
5773  grn_hash *hash = (grn_hash *)obj;
5774  uint32_t size = hash->value_size;
5775  grn_obj_ensure_bulk(ctx, value);
5776  if (grn_bulk_space(ctx, value, size)) {
5777  MERR("grn_bulk_space failed");
5778  goto exit;
5779  }
5780  {
5781  char *curr = GRN_BULK_CURR(value);
5782  grn_hash_get_value(ctx, hash, id, curr - size);
5783  }
5784  value->header.type = GRN_BULK;
5785  value->header.domain = grn_obj_get_range(ctx, obj);
5786  }
5787  break;
5788  case GRN_TABLE_NO_KEY :
5789  {
5790  grn_array *array = (grn_array *)obj;
5791  uint32_t size = array->value_size;
5792  grn_obj_ensure_bulk(ctx, value);
5793  if (grn_bulk_space(ctx, value, size)) {
5794  MERR("grn_bulk_space failed");
5795  goto exit;
5796  }
5797  {
5798  char *curr = GRN_BULK_CURR(value);
5799  grn_array_get_value(ctx, array, id, curr - size);
5800  }
5801  value->header.type = GRN_BULK;
5802  value->header.domain = grn_obj_get_range(ctx, obj);
5803  }
5804  break;
5805  case GRN_COLUMN_VAR_SIZE :
5806  switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
5807  case GRN_OBJ_COLUMN_VECTOR :
5808  {
5809  grn_obj *lexicon = grn_ctx_at(ctx, DB_OBJ(obj)->range);
5810  if (lexicon && !GRN_OBJ_TABLEP(lexicon) &&
5811  (lexicon->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
5812  grn_obj v_;
5813  grn_obj_ensure_vector(ctx, value);
5814  GRN_TEXT_INIT(&v_, 0);
5815  grn_ja_get_value(ctx, (grn_ja *)obj, id, &v_);
5816  grn_vector_decode(ctx, value, GRN_TEXT_VALUE(&v_), GRN_TEXT_LEN(&v_));
5817  GRN_OBJ_FIN(ctx, &v_);
5818  } else {
5819  grn_obj_ensure_bulk(ctx, value);
5820  grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
5821  value->header.type = GRN_UVECTOR;
5822  }
5823  }
5824  break;
5825  case GRN_OBJ_COLUMN_SCALAR :
5826  grn_obj_ensure_bulk(ctx, value);
5827  grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
5828  value->header.type = GRN_BULK;
5829  break;
5830  default :
5831  ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
5832  break;
5833  }
5834  value->header.domain = grn_obj_get_range(ctx, obj);
5835  break;
5836  case GRN_COLUMN_FIX_SIZE :
5837  {
5838  unsigned int element_size;
5839  void *v = grn_ra_ref(ctx, (grn_ra *)obj, id);
5840  grn_obj_ensure_bulk(ctx, value);
5841  value->header.type = GRN_BULK;
5842  value->header.domain = grn_obj_get_range(ctx, obj);
5843  if (v) {
5844  element_size = ((grn_ra *)obj)->header->element_size;
5845  grn_bulk_write(ctx, value, v, element_size);
5846  grn_ra_unref(ctx, (grn_ra *)obj, id);
5847  }
5848  }
5849  break;
5850  case GRN_COLUMN_INDEX :
5851  grn_obj_ensure_bulk(ctx, value);
5852  GRN_UINT32_SET(ctx, value, grn_ii_estimate_size(ctx, (grn_ii *)obj, id));
5853  value->header.domain = GRN_DB_UINT32;
5854  break;
5855  }
5856 exit :
5857  GRN_API_RETURN(value);
5858 }
5859 
5860 int
5861 grn_obj_get_values(grn_ctx *ctx, grn_obj *obj, grn_id offset, void **values)
5862 {
5863  int nrecords = -1;
5864  GRN_API_ENTER;
5865  if (obj->header.type == GRN_COLUMN_FIX_SIZE) {
5866  grn_obj *domain = grn_column_table(ctx, obj);
5867  if (domain) {
5868  int table_size = (int)grn_table_size(ctx, domain);
5869  if (0 < offset && offset <= table_size) {
5870  grn_ra *ra = (grn_ra *)obj;
5871  void *p = grn_ra_ref(ctx, ra, offset);
5872  if (p) {
5873  if ((offset >> ra->element_width) == (table_size >> ra->element_width)) {
5874  nrecords = (table_size & ra->element_mask) + 1 - (offset & ra->element_mask);
5875  } else {
5876  nrecords = ra->element_mask + 1 - (offset & ra->element_mask);
5877  }
5878  if (values) { *values = p; }
5879  grn_ra_unref(ctx, ra, offset);
5880  } else {
5881  ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
5882  }
5883  } else {
5884  nrecords = 0;
5885  }
5886  } else {
5887  ERR(GRN_INVALID_ARGUMENT, "no domain found");
5888  }
5889  } else {
5890  ERR(GRN_INVALID_ARGUMENT, "obj is not a fix sized column");
5891  }
5892  GRN_API_RETURN(nrecords);
5893 }
5894 
5895 grn_rc
5897  grn_id id, unsigned int section,
5898  grn_obj *oldvalue, grn_obj *newvalue)
5899 {
5901  GRN_API_ENTER;
5902  if (column->header.type != GRN_COLUMN_INDEX) {
5903  ERR(GRN_INVALID_ARGUMENT, "invalid column assigned");
5904  } else {
5905  rc = grn_ii_column_update(ctx, (grn_ii *)column, id, section, oldvalue, newvalue, NULL);
5906  }
5907  GRN_API_RETURN(rc);
5908 }
5909 
5910 grn_obj *
5912 {
5913  grn_obj *obj = NULL;
5914  grn_db_obj *col = DB_OBJ(column);
5915  GRN_API_ENTER;
5916  if (col) {
5917  obj = grn_ctx_at(ctx, col->header.domain);
5918  }
5919  GRN_API_RETURN(obj);
5920 }
5921 
5922 grn_obj *
5924 {
5925  GRN_API_ENTER;
5926  switch (type) {
5927  case GRN_INFO_SUPPORT_ZLIB :
5928  if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
5930  "failed to open value buffer for GRN_INFO_ZLIB_SUPPORT");
5931  goto exit;
5932  }
5933 #ifdef GRN_WITH_ZLIB
5934  GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
5935 #else
5936  GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
5937 #endif
5938  break;
5939  case GRN_INFO_SUPPORT_LZO :
5940  if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
5942  "failed to open value buffer for GRN_INFO_LZO_SUPPORT");
5943  goto exit;
5944  }
5945 #ifdef GRN_WITH_LZO
5946  GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
5947 #else /* GRN_WITH_LZO */
5948  GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
5949 #endif /* GRN_WITH_LZO */
5950  break;
5951  default :
5952  if (!obj) {
5953  ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
5954  goto exit;
5955  }
5956  switch (type) {
5957  case GRN_INFO_ENCODING :
5958  if (!valuebuf) {
5959  if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
5960  ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
5961  goto exit;
5962  }
5963  }
5964  {
5965  grn_encoding enc;
5966  if (obj->header.type == GRN_DB) { obj = ((grn_db *)obj)->keys; }
5967  switch (obj->header.type) {
5968  case GRN_TABLE_PAT_KEY :
5969  enc = ((grn_pat *)obj)->encoding;
5970  grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
5971  break;
5972  case GRN_TABLE_DAT_KEY :
5973  enc = ((grn_dat *)obj)->encoding;
5974  grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
5975  break;
5976  case GRN_TABLE_HASH_KEY :
5977  enc = ((grn_hash *)obj)->encoding;
5978  grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
5979  break;
5980  default :
5981  ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
5982  }
5983  }
5984  break;
5985  case GRN_INFO_SOURCE :
5986  if (!valuebuf) {
5987  if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
5988  ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
5989  goto exit;
5990  }
5991  }
5992  if (!GRN_DB_OBJP(obj)) {
5993  ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
5994  goto exit;
5995  }
5996  grn_bulk_write(ctx, valuebuf, DB_OBJ(obj)->source, DB_OBJ(obj)->source_size);
5997  break;
5999  switch (DB_OBJ(obj)->header.type) {
6000  case GRN_TABLE_HASH_KEY :
6001  valuebuf = ((grn_hash *)obj)->tokenizer;
6002  break;
6003  case GRN_TABLE_PAT_KEY :
6004  valuebuf = ((grn_pat *)obj)->tokenizer;
6005  break;
6006  case GRN_TABLE_DAT_KEY :
6007  valuebuf = ((grn_dat *)obj)->tokenizer;
6008  break;
6009  }
6010  break;
6011  case GRN_INFO_NORMALIZER :
6012  switch (DB_OBJ(obj)->header.type) {
6013  case GRN_TABLE_HASH_KEY :
6014  valuebuf = ((grn_hash *)obj)->normalizer;
6015  break;
6016  case GRN_TABLE_PAT_KEY :
6017  valuebuf = ((grn_pat *)obj)->normalizer;
6018  break;
6019  case GRN_TABLE_DAT_KEY :
6020  valuebuf = ((grn_dat *)obj)->normalizer;
6021  break;
6022  }
6023  break;
6024  default :
6025  /* todo */
6026  break;
6027  }
6028  }
6029 exit :
6030  GRN_API_RETURN(valuebuf);
6031 }
6032 
6033 static void
6034 build_index(grn_ctx *ctx, grn_obj *obj)
6035 {
6036  grn_obj *src, **cp, **col, *target;
6037  grn_id *s = DB_OBJ(obj)->source;
6038  if (!(DB_OBJ(obj)->source_size) || !s) { return; }
6039  if ((src = grn_ctx_at(ctx, *s))) {
6040  target = GRN_OBJ_TABLEP(src) ? src : grn_ctx_at(ctx, src->header.domain);
6041  if (target) {
6042  int i, ncol = DB_OBJ(obj)->source_size / sizeof(grn_id);
6043  grn_obj_flags flags;
6044  grn_ii *ii = (grn_ii *)obj;
6045  grn_bool use_grn_ii_build;
6046  grn_table_get_info(ctx, ii->lexicon, &flags, NULL, NULL, NULL);
6047  switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
6048  case GRN_OBJ_TABLE_PAT_KEY :
6049  case GRN_OBJ_TABLE_DAT_KEY :
6050  use_grn_ii_build = GRN_TRUE;
6051  break;
6052  default :
6053  use_grn_ii_build = GRN_FALSE;
6054  }
6055  if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
6056  use_grn_ii_build = GRN_FALSE;
6057  }
6058  if ((col = GRN_MALLOC(ncol * sizeof(grn_obj *)))) {
6059  for (cp = col, i = ncol; i; s++, cp++, i--) {
6060  if (!(*cp = grn_ctx_at(ctx, *s))) {
6061  ERR(GRN_INVALID_ARGUMENT, "source invalid, n=%d",i);
6062  GRN_FREE(col);
6063  return;
6064  }
6065  if (GRN_OBJ_TABLEP(grn_ctx_at(ctx, DB_OBJ(*cp)->range))) {
6066  use_grn_ii_build = GRN_FALSE;
6067  }
6068  }
6069  if (use_grn_ii_build) {
6070  uint64_t sparsity = 10;
6071  if (getenv("GRN_INDEX_SPARSITY")) {
6072  uint64_t v;
6073  errno = 0;
6074  v = strtoull(getenv("GRN_INDEX_SPARSITY"), NULL, 0);
6075  if (!errno) { sparsity = v; }
6076  }
6077  grn_ii_build(ctx, ii, sparsity);
6078  } else {
6079  grn_table_cursor *tc;
6080  if ((tc = grn_table_cursor_open(ctx, target, NULL, 0, NULL, 0,
6081  0, -1, GRN_CURSOR_BY_ID))) {
6082  grn_id id;
6083  grn_obj rv;
6084  GRN_TEXT_INIT(&rv, 0);
6085  while ((id = grn_table_cursor_next_inline(ctx, tc)) != GRN_ID_NIL) {
6086  for (cp = col, i = ncol; i; i--, cp++) {
6087  GRN_BULK_REWIND(&rv);
6088  if (GRN_OBJ_TABLEP(*cp)) {
6089  grn_table_get_key2(ctx, *cp, id, &rv);
6090  } else {
6091  grn_obj_get_value(ctx, *cp, id, &rv);
6092  }
6093  call_hook_for_build(ctx, *cp, id, &rv, 0);
6094  }
6095  }
6096  GRN_OBJ_FIN(ctx, &rv);
6097  grn_table_cursor_close(ctx, tc);
6098  }
6099  }
6100  GRN_FREE(col);
6101  }
6102  } else {
6103  ERR(GRN_INVALID_ARGUMENT, "invalid target");
6104  }
6105  } else {
6106  ERR(GRN_INVALID_ARGUMENT, "invalid source");
6107  }
6108 }
6109 
6110 static void
6111 update_source_hook(grn_ctx *ctx, grn_obj *obj)
6112 {
6113  grn_id *s = DB_OBJ(obj)->source;
6114  int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
6115  default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
6116  grn_obj *source, data;
6118  GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
6119  for (i = 1; i <= n; i++, s++) {
6120  hook_data.section = i;
6121  if ((source = grn_ctx_at(ctx, *s))) {
6122  switch (source->header.type) {
6123  case GRN_TABLE_HASH_KEY :
6124  case GRN_TABLE_PAT_KEY :
6125  case GRN_TABLE_DAT_KEY :
6126  grn_obj_add_hook(ctx, source, GRN_HOOK_INSERT, 0, NULL, &data);
6127  grn_obj_add_hook(ctx, source, GRN_HOOK_DELETE, 0, NULL, &data);
6128  break;
6129  case GRN_COLUMN_FIX_SIZE :
6130  case GRN_COLUMN_VAR_SIZE :
6131  grn_obj_add_hook(ctx, source, GRN_HOOK_SET, 0, NULL, &data);
6132  break;
6133  default :
6134  /* invalid target */
6135  break;
6136  }
6137  }
6138  }
6139  grn_obj_close(ctx, &data);
6140 }
6141 
6142 static void
6143 del_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, grn_obj *hld)
6144 {
6145  int i;
6146  void *hld_value = NULL;
6147  uint32_t hld_size = 0;
6148  grn_hook **last;
6149  hld_value = GRN_BULK_HEAD(hld);
6150  hld_size = GRN_BULK_VSIZE(hld);
6151  if (!hld_size) { return; }
6152  for (i = 0, last = &DB_OBJ(obj)->hooks[entry]; *last; i++, last = &(*last)->next) {
6153  if (!memcmp(NEXT_ADDR(*last), hld_value, hld_size)) {
6154  grn_obj_delete_hook(ctx, obj, entry, i);
6155  return;
6156  }
6157  }
6158 }
6159 
6160 static void
6161 delete_source_hook(grn_ctx *ctx, grn_obj *obj)
6162 {
6163  grn_id *s = DB_OBJ(obj)->source;
6164  int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
6165  default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
6166  grn_obj *source, data;
6168  GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
6169  for (i = 1; i <= n; i++, s++) {
6170  hook_data.section = i;
6171  if ((source = grn_ctx_at(ctx, *s))) {
6172  switch (source->header.type) {
6173  case GRN_TABLE_HASH_KEY :
6174  case GRN_TABLE_PAT_KEY :
6175  case GRN_TABLE_DAT_KEY :
6176  del_hook(ctx, source, GRN_HOOK_INSERT, &data);
6177  del_hook(ctx, source, GRN_HOOK_DELETE, &data);
6178  break;
6179  case GRN_COLUMN_FIX_SIZE :
6180  case GRN_COLUMN_VAR_SIZE :
6181  del_hook(ctx, source, GRN_HOOK_SET, &data);
6182  break;
6183  default :
6184  /* invalid target */
6185  break;
6186  }
6187  }
6188  }
6189  grn_obj_close(ctx, &data);
6190 }
6191 
6192 #define N_HOOK_ENTRIES 5
6193 
6194 grn_rc
6196 {
6197  grn_rc rc;
6198  grn_hook_entry e;
6199  for (e = 0; e < N_HOOK_ENTRIES; e++) {
6200  grn_hook *hooks;
6201  for (hooks = obj->hooks[e]; hooks; hooks = hooks->next) {
6202  grn_id id = hooks->proc ? hooks->proc->obj.id : 0;
6203  if ((rc = grn_text_benc(ctx, buf, id + 1))) { goto exit; }
6204  if ((rc = grn_text_benc(ctx, buf, hooks->hld_size))) { goto exit; }
6205  if ((rc = grn_bulk_write(ctx, buf, (char *)NEXT_ADDR(hooks), hooks->hld_size))) { goto exit; }
6206  }
6207  if ((rc = grn_text_benc(ctx, buf, 0))) { goto exit; }
6208  }
6209 exit :
6210  return rc;
6211 }
6212 
6213 static grn_rc
6214 grn_hook_unpack(grn_ctx *ctx, grn_db_obj *obj, const char *buf, uint32_t buf_size)
6215 {
6216  grn_hook_entry e;
6217  const uint8_t *p = (uint8_t *)buf, *pe = p + buf_size;
6218  for (e = 0; e < N_HOOK_ENTRIES; e++) {
6219  grn_hook *new, **last = &obj->hooks[e];
6220  for (;;) {
6221  grn_id id;
6222  uint32_t hld_size;
6223  GRN_B_DEC(id, p);
6224  if (!id--) { break; }
6225  if (p >= pe) { return GRN_FILE_CORRUPT; }
6226  GRN_B_DEC(hld_size, p);
6227  if (p >= pe) { return GRN_FILE_CORRUPT; }
6228  if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
6229  return GRN_NO_MEMORY_AVAILABLE;
6230  }
6231  if (id) {
6232  new->proc = (grn_proc *)grn_ctx_at(ctx, id);
6233  if (!new->proc) {
6234  GRN_FREE(new);
6235  return ctx->rc;
6236  }
6237  } else {
6238  new->proc = NULL;
6239  }
6240  if ((new->hld_size = hld_size)) {
6241  memcpy(NEXT_ADDR(new), p, hld_size);
6242  p += hld_size;
6243  }
6244  *last = new;
6245  last = &new->next;
6246  if (p >= pe) { return GRN_FILE_CORRUPT; }
6247  }
6248  *last = NULL;
6249  }
6250  return GRN_SUCCESS;
6251 }
6252 
6253 void
6255 {
6256  grn_db *s;
6257  grn_obj v, *b;
6258  grn_obj_spec spec;
6259  if (obj->id & GRN_OBJ_TMP_OBJECT) { return; }
6260  if (!ctx->impl || !GRN_DB_OBJP(obj)) { return; }
6261  if (!(s = (grn_db *)ctx->impl->db) || !s->specs) { return; }
6263  if (!(b = grn_vector_body(ctx, &v))) { return; }
6264  spec.header = obj->header;
6265  spec.range = obj->range;
6266  grn_bulk_write(ctx, b, (void *)&spec, sizeof(grn_obj_spec));
6267  grn_vector_delimit(ctx, &v, 0, 0);
6268  if (obj->header.flags & GRN_OBJ_CUSTOM_NAME) {
6269  GRN_TEXT_PUTS(ctx, b, grn_obj_path(ctx, (grn_obj *)obj));
6270  }
6271  grn_vector_delimit(ctx, &v, 0, 0);
6272  grn_bulk_write(ctx, b, obj->source, obj->source_size);
6273  grn_vector_delimit(ctx, &v, 0, 0);
6274  grn_hook_pack(ctx, obj, b);
6275  grn_vector_delimit(ctx, &v, 0, 0);
6276  switch (obj->header.type) {
6277  case GRN_EXPR :
6278  grn_expr_pack(ctx, b, (grn_obj *)obj);
6279  grn_vector_delimit(ctx, &v, 0, 0);
6280  break;
6281  }
6282  grn_ja_putv(ctx, s->specs, obj->id, &v, 0);
6283  grn_obj_close(ctx, &v);
6284 }
6285 
6286 inline static grn_rc
6287 grn_obj_set_info_source_validate_report_error(grn_ctx *ctx,
6288  grn_obj *column,
6289  grn_obj *table_domain,
6290  grn_obj *source,
6291  grn_id source_type_id)
6292 {
6293  char column_name[GRN_TABLE_MAX_KEY_SIZE];
6294  char table_domain_name[GRN_TABLE_MAX_KEY_SIZE];
6295  char source_name[GRN_TABLE_MAX_KEY_SIZE];
6296  char source_type_name[GRN_TABLE_MAX_KEY_SIZE];
6297  int column_name_size;
6298  int table_domain_name_size;
6299  int source_name_size;
6300  int source_type_name_size;
6301  grn_obj *source_type;
6302 
6303  column_name_size = grn_obj_name(ctx, column,
6304  column_name, GRN_TABLE_MAX_KEY_SIZE);
6305  source_name_size = grn_obj_name(ctx, source,
6306  source_name, GRN_TABLE_MAX_KEY_SIZE);
6307  if (GRN_OBJ_TABLEP(source)) {
6308  source_name[source_name_size] = '\0';
6309  strncat(source_name, "._key",
6310  GRN_TABLE_MAX_KEY_SIZE - source_name_size - 1);
6311  source_name_size = strlen(source_name);
6312  }
6313  table_domain_name_size = grn_obj_name(ctx, table_domain,
6314  table_domain_name,
6316  source_type = grn_ctx_at(ctx, source_type_id);
6317  if (source_type) {
6318  source_type_name_size = grn_obj_name(ctx, source_type,
6319  source_type_name,
6321  grn_obj_unlink(ctx, source_type);
6322  } else {
6323  strncpy(source_type_name, "(nil)", GRN_TABLE_MAX_KEY_SIZE);
6324  source_type_name_size = strlen(source_type_name);
6325  }
6327  "grn_obj_set_info(): GRN_INFO_SOURCE: "
6328  "source type must equal to index table's key type: "
6329  "source:<%.*s(%.*s)> index:<%.*s(%.*s)>",
6330  source_name_size, source_name,
6331  source_type_name_size, source_type_name,
6332  column_name_size, column_name,
6333  table_domain_name_size, table_domain_name);
6334  return ctx->rc;
6335 }
6336 
6337 inline static grn_rc
6338 grn_obj_set_info_source_validate(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
6339 {
6340  grn_rc rc = GRN_SUCCESS;
6341  grn_id table_id;
6342  grn_obj *table = NULL;
6343  grn_id table_domain_id;
6344  grn_obj *table_domain = NULL;
6345  grn_id *source_ids;
6346  int i, n_source_ids;
6347 
6348  table_id = obj->header.domain;
6349  table = grn_ctx_at(ctx, table_id);
6350  if (!table) {
6351  goto exit;
6352  }
6353 
6354  table_domain_id = table->header.domain;
6355  table_domain = grn_ctx_at(ctx, table_domain_id);
6356  if (!table_domain) {
6357  goto exit;
6358  }
6359 
6360  if (!GRN_OBJ_TABLEP(table_domain)) {
6361  goto exit;
6362  }
6363 
6364  source_ids = (grn_id *)GRN_BULK_HEAD(value);
6365  n_source_ids = GRN_BULK_VSIZE(value) / sizeof(grn_id);
6366  for (i = 0; i < n_source_ids; i++) {
6367  grn_id source_id = source_ids[i];
6368  grn_obj *source;
6369  grn_id source_type_id;
6370 
6371  source = grn_ctx_at(ctx, source_id);
6372  if (!source) {
6373  continue;
6374  }
6375  if (GRN_OBJ_TABLEP(source)) {
6376  source_type_id = source->header.domain;
6377  } else {
6378  source_type_id = DB_OBJ(source)->range;
6379  }
6380  if (table_domain_id != source_type_id) {
6381  rc = grn_obj_set_info_source_validate_report_error(ctx,
6382  obj,
6383  table_domain,
6384  source,
6385  source_type_id);
6386  }
6387  grn_obj_unlink(ctx, source);
6388  if (rc != GRN_SUCCESS) {
6389  goto exit;
6390  }
6391  }
6392 
6393 exit:
6394  if (table) {
6395  grn_obj_unlink(ctx, table);
6396  }
6397  if (table_domain) {
6398  grn_obj_unlink(ctx, table_domain);
6399  }
6400  return GRN_SUCCESS;
6401 }
6402 
6403 inline static void
6404 grn_obj_set_info_source_log(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
6405 {
6406  grn_obj buf;
6407  grn_id *vp = (grn_id *)GRN_BULK_HEAD(value);
6408  uint32_t vs = GRN_BULK_VSIZE(value), s = 0;
6409  const char *n = _grn_table_key(ctx, ctx->impl->db, DB_OBJ(obj)->id, &s);
6410  GRN_TEXT_INIT(&buf, 0);
6411  GRN_TEXT_PUT(ctx, &buf, n, s);
6412  GRN_TEXT_PUTC(ctx, &buf, ' ');
6413  while (vs) {
6414  n = _grn_table_key(ctx, ctx->impl->db, *vp++, &s);
6415  GRN_TEXT_PUT(ctx, &buf, n, s);
6416  vs -= sizeof(grn_id);
6417  if (vs) { GRN_TEXT_PUTC(ctx, &buf, ','); }
6418  }
6419  GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:set_source %.*s",
6420  (int)GRN_BULK_VSIZE(&buf), GRN_BULK_HEAD(&buf));
6421  GRN_OBJ_FIN(ctx, &buf);
6422 }
6423 
6424 inline static grn_rc
6425 grn_obj_set_info_source_update(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
6426 {
6427  void *v = GRN_BULK_HEAD(value);
6428  uint32_t s = GRN_BULK_VSIZE(value);
6429  if (s) {
6430  void *v2 = GRN_MALLOC(s);
6431  if (!v2) {
6432  return ctx->rc;
6433  }
6434  memcpy(v2, v, s);
6435  if (DB_OBJ(obj)->source) { GRN_FREE(DB_OBJ(obj)->source); }
6436  DB_OBJ(obj)->source = v2;
6437  DB_OBJ(obj)->source_size = s;
6438 
6439  if (obj->header.type == GRN_COLUMN_INDEX) {
6440  update_source_hook(ctx, obj);
6441  build_index(ctx, obj);
6442  }
6443  } else {
6444  DB_OBJ(obj)->source = NULL;
6445  DB_OBJ(obj)->source_size = 0;
6446  }
6447 
6448  return GRN_SUCCESS;
6449 }
6450 
6451 inline static grn_rc
6452 grn_obj_set_info_source(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
6453 {
6454  grn_rc rc;
6455 
6456  rc = grn_obj_set_info_source_validate(ctx, obj, value);
6457  if (rc != GRN_SUCCESS) {
6458  return rc;
6459  }
6460  grn_obj_set_info_source_log(ctx, obj, value);
6461  rc = grn_obj_set_info_source_update(ctx, obj, value);
6462  if (rc != GRN_SUCCESS) {
6463  return rc;
6464  }
6465  grn_obj_spec_save(ctx, DB_OBJ(obj));
6466 
6467  return rc;
6468 }
6469 
6470 grn_rc
6472 {
6474  GRN_API_ENTER;
6475  if (!obj) {
6476  ERR(GRN_INVALID_ARGUMENT, "grn_obj_set_info failed");
6477  goto exit;
6478  }
6479  switch (type) {
6480  case GRN_INFO_SOURCE :
6481  if (!GRN_DB_OBJP(obj)) {
6482  ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
6483  goto exit;
6484  }
6485  rc = grn_obj_set_info_source(ctx, obj, value);
6486  break;
6488  if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
6489  switch (DB_OBJ(obj)->header.type) {
6490  case GRN_TABLE_HASH_KEY :
6491  ((grn_hash *)obj)->tokenizer = value;
6492  ((grn_hash *)obj)->header->tokenizer = grn_obj_id(ctx, value);
6493  rc = GRN_SUCCESS;
6494  break;
6495  case GRN_TABLE_PAT_KEY :
6496  ((grn_pat *)obj)->tokenizer = value;
6497  ((grn_pat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
6498  rc = GRN_SUCCESS;
6499  break;
6500  case GRN_TABLE_DAT_KEY :
6501  ((grn_dat *)obj)->tokenizer = value;
6502  ((grn_dat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
6503  rc = GRN_SUCCESS;
6504  break;
6505  }
6506  }
6507  break;
6508  case GRN_INFO_NORMALIZER :
6509  if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
6510  switch (DB_OBJ(obj)->header.type) {
6511  case GRN_TABLE_HASH_KEY :
6512  ((grn_hash *)obj)->normalizer = value;
6513  ((grn_hash *)obj)->header->normalizer = grn_obj_id(ctx, value);
6514  rc = GRN_SUCCESS;
6515  break;
6516  case GRN_TABLE_PAT_KEY :
6517  ((grn_pat *)obj)->normalizer = value;
6518  ((grn_pat *)obj)->header->normalizer = grn_obj_id(ctx, value);
6519  rc = GRN_SUCCESS;
6520  break;
6521  case GRN_TABLE_DAT_KEY :
6522  ((grn_dat *)obj)->normalizer = value;
6523  ((grn_dat *)obj)->header->normalizer = grn_obj_id(ctx, value);
6524  rc = GRN_SUCCESS;
6525  break;
6526  }
6527  }
6528  break;
6529  default :
6530  /* todo */
6531  break;
6532  }
6533 exit :
6534  GRN_API_RETURN(rc);
6535 }
6536 
6537 grn_obj *
6539  grn_info_type type, grn_obj *valuebuf)
6540 {
6541  GRN_API_ENTER;
6542  GRN_API_RETURN(valuebuf);
6543 }
6544 
6545 grn_rc
6547  grn_info_type type, grn_obj *value)
6548 {
6549  GRN_API_ENTER;
6551 }
6552 
6553 grn_bool
6555 {
6556  grn_id id;
6557 
6558  if (!obj) { return GRN_FALSE; }
6559 
6560  id = grn_obj_id(ctx, obj);
6561  if (id == GRN_ID_NIL) {
6562  return GRN_FALSE;
6563  } else {
6564  return id < GRN_N_RESERVED_TYPES;
6565  }
6566 }
6567 
6568 static void
6569 grn_hook_free(grn_ctx *ctx, grn_hook *h)
6570 {
6571  grn_hook *curr, *next;
6572  for (curr = h; curr; curr = next) {
6573  next = curr->next;
6574  GRN_FREE(curr);
6575  }
6576 }
6577 
6578 grn_rc
6580  int offset, grn_obj *proc, grn_obj *hld)
6581 {
6582  grn_rc rc = GRN_SUCCESS;
6583  GRN_API_ENTER;
6584  if (!GRN_DB_OBJP(obj)) {
6585  rc = GRN_INVALID_ARGUMENT;
6586  } else {
6587  int i;
6588  void *hld_value = NULL;
6589  uint32_t hld_size = 0;
6590  grn_hook *new, **last = &DB_OBJ(obj)->hooks[entry];
6591  if (hld) {
6592  hld_value = GRN_BULK_HEAD(hld);
6593  hld_size = GRN_BULK_VSIZE(hld);
6594  }
6595  if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
6597  goto exit;
6598  }
6599  new->proc = (grn_proc *)proc;
6600  new->hld_size = hld_size;
6601  if (hld_size) {
6602  memcpy(NEXT_ADDR(new), hld_value, hld_size);
6603  }
6604  for (i = 0; i != offset && *last; i++) { last = &(*last)->next; }
6605  new->next = *last;
6606  *last = new;
6607  grn_obj_spec_save(ctx, DB_OBJ(obj));
6608  }
6609 exit :
6610  GRN_API_RETURN(rc);
6611 }
6612 
6613 int
6615 {
6616  int res = 0;
6617  GRN_API_ENTER;
6618  {
6619  grn_hook *hook = DB_OBJ(obj)->hooks[entry];
6620  while (hook) {
6621  res++;
6622  hook = hook->next;
6623  }
6624  }
6625  GRN_API_RETURN(res);
6626 }
6627 
6628 grn_obj *
6630  int offset, grn_obj *hldbuf)
6631 {
6632  grn_obj *res = NULL;
6633  GRN_API_ENTER;
6634  {
6635  int i;
6636  grn_hook *hook = DB_OBJ(obj)->hooks[entry];
6637  for (i = 0; i < offset; i++) {
6638  hook = hook->next;
6639  if (!hook) { return NULL; }
6640  }
6641  res = (grn_obj *)hook->proc;
6642  grn_bulk_write(ctx, hldbuf, (char *)NEXT_ADDR(hook), hook->hld_size);
6643  }
6644  GRN_API_RETURN(res);
6645 }
6646 
6647 grn_rc
6648 grn_obj_delete_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, int offset)
6649 {
6650  GRN_API_ENTER;
6651  {
6652  int i = 0;
6653  grn_hook *h, **last = &DB_OBJ(obj)->hooks[entry];
6654  for (;;) {
6655  if (!(h = *last)) { return GRN_INVALID_ARGUMENT; }
6656  if (++i > offset) { break; }
6657  last = &h->next;
6658  }
6659  *last = h->next;
6660  GRN_FREE(h);
6661  }
6662  grn_obj_spec_save(ctx, DB_OBJ(obj));
6664 }
6665 
6666 static void
6667 remove_index(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry)
6668 {
6669  grn_hook *h0, *hooks = DB_OBJ(obj)->hooks[entry];
6670  DB_OBJ(obj)->hooks[entry] = NULL; /* avoid mutual recursive call */
6671  while (hooks) {
6672  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
6673  grn_obj *target = grn_ctx_at(ctx, data->target);
6674  if (!target) {
6675  char name[GRN_TABLE_MAX_KEY_SIZE];
6676  int length;
6677  length = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
6679  "[column][remove][index] "
6680  "hook has a dangling reference: %.*s", length, name);
6681  } else if (target->header.type == GRN_COLUMN_INDEX) {
6682  //TODO: multicolumn MULTI_COLUMN_INDEXP
6683  _grn_obj_remove(ctx, target);
6684  } else {
6685  //TODO: err
6686  char fn[GRN_TABLE_MAX_KEY_SIZE];
6687  int flen;
6688  flen = grn_obj_name(ctx, target, fn, GRN_TABLE_MAX_KEY_SIZE);
6689  fn[flen] = '\0';
6690  ERR(GRN_UNKNOWN_ERROR, "column has unsupported hooks, col=%s",fn);
6691  }
6692  h0 = hooks;
6693  hooks = hooks->next;
6694  GRN_FREE(h0);
6695  }
6696 }
6697 
6698 static void
6699 remove_columns(grn_ctx *ctx, grn_obj *obj)
6700 {
6701  grn_hash *cols;
6702  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
6704  if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
6705  grn_id *key;
6706  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
6707  grn_obj *col = grn_ctx_at(ctx, *key);
6708  if (col) { _grn_obj_remove(ctx, col); }
6709  });
6710  }
6711  grn_hash_close(ctx, cols);
6712  }
6713 }
6714 
6715 static void
6716 _grn_obj_remove_db_index_columns(grn_ctx *ctx, grn_obj *db)
6717 {
6718  grn_table_cursor *cur;
6719  if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
6720  grn_id id;
6721  while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
6722  grn_obj *obj = grn_ctx_at(ctx, id);
6723  if (obj && obj->header.type == GRN_COLUMN_INDEX) {
6724  _grn_obj_remove(ctx, obj);
6725  }
6726  }
6727  grn_table_cursor_close(ctx, cur);
6728  }
6729 }
6730 
6731 static void
6732 _grn_obj_remove_db_reference_columns(grn_ctx *ctx, grn_obj *db)
6733 {
6734  grn_table_cursor *cur;
6735  if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
6736  grn_id id;
6737  while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
6738  grn_obj *obj = grn_ctx_at(ctx, id);
6739  grn_obj *range = NULL;
6740 
6741  if (!obj) {
6742  continue;
6743  }
6744 
6745  switch (obj->header.type) {
6746  case GRN_COLUMN_FIX_SIZE :
6747  case GRN_COLUMN_VAR_SIZE :
6748  if (!DB_OBJ(obj)->range) {
6749  break;
6750  }
6751 
6752  range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
6753  if (!range) {
6754  break;
6755  }
6756 
6757  switch (range->header.type) {
6758  case GRN_TABLE_NO_KEY :
6759  case GRN_TABLE_HASH_KEY :
6760  case GRN_TABLE_PAT_KEY :
6761  case GRN_TABLE_DAT_KEY :
6762  _grn_obj_remove(ctx, obj);
6763  break;
6764  }
6765  break;
6766  }
6767  }
6768  grn_table_cursor_close(ctx, cur);
6769  }
6770 }
6771 
6772 static void
6773 _grn_obj_remove_db_reference_tables(grn_ctx *ctx, grn_obj *db)
6774 {
6775  grn_table_cursor *cur;
6776  if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
6777  grn_id id;
6778  while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
6779  grn_obj *obj = grn_ctx_at(ctx, id);
6780  grn_obj *domain = NULL;
6781 
6782  if (!obj) {
6783  continue;
6784  }
6785 
6786  switch (obj->header.type) {
6787  case GRN_TABLE_HASH_KEY :
6788  case GRN_TABLE_PAT_KEY :
6789  case GRN_TABLE_DAT_KEY :
6790  if (!obj->header.domain) {
6791  break;
6792  }
6793 
6794  domain = grn_ctx_at(ctx, obj->header.domain);
6795  if (!domain) {
6796  break;
6797  }
6798 
6799  switch (domain->header.type) {
6800  case GRN_TABLE_NO_KEY :
6801  case GRN_TABLE_HASH_KEY :
6802  case GRN_TABLE_PAT_KEY :
6803  case GRN_TABLE_DAT_KEY :
6804  _grn_obj_remove(ctx, obj);
6805  break;
6806  }
6807  break;
6808  }
6809  }
6810  grn_table_cursor_close(ctx, cur);
6811  }
6812 }
6813 
6814 static void
6815 _grn_obj_remove_db_all_tables(grn_ctx *ctx, grn_obj *db)
6816 {
6817  grn_table_cursor *cur;
6818  if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
6819  grn_id id;
6820  while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
6821  grn_obj *obj = grn_ctx_at(ctx, id);
6822 
6823  if (!obj) {
6824  continue;
6825  }
6826 
6827  switch (obj->header.type) {
6828  case GRN_TABLE_NO_KEY :
6829  case GRN_TABLE_HASH_KEY :
6830  case GRN_TABLE_PAT_KEY :
6831  case GRN_TABLE_DAT_KEY :
6832  _grn_obj_remove(ctx, obj);
6833  break;
6834  }
6835  }
6836  grn_table_cursor_close(ctx, cur);
6837  }
6838 }
6839 
6840 static void
6841 _grn_obj_remove_db(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
6842  const char *path)
6843 {
6844  const char *io_spath;
6845  char *spath;
6846  grn_db *s = (grn_db *)db;
6847  unsigned char key_type;
6848 
6849  if (s->specs &&
6850  (io_spath = grn_obj_path(ctx, (grn_obj *)s->specs)) && *io_spath != '\0') {
6851  if (!(spath = GRN_STRDUP(io_spath))) {
6852  ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_spath);
6853  return;
6854  }
6855  } else {
6856  spath = NULL;
6857  }
6858 
6859  key_type = s->keys->header.type;
6860 
6861  _grn_obj_remove_db_index_columns(ctx, db);
6862  _grn_obj_remove_db_reference_columns(ctx, db);
6863  _grn_obj_remove_db_reference_tables(ctx, db);
6864  _grn_obj_remove_db_all_tables(ctx, db);
6865 
6866  grn_obj_close(ctx, obj);
6867 
6868  if (spath) {
6869  grn_ja_remove(ctx, spath);
6870  GRN_FREE(spath);
6871  }
6872 
6873  if (path) {
6874  switch (key_type) {
6875  case GRN_TABLE_PAT_KEY :
6876  grn_pat_remove(ctx, path);
6877  break;
6878  case GRN_TABLE_DAT_KEY :
6879  grn_dat_remove(ctx, path);
6880  break;
6881  }
6882  }
6883 }
6884 
6885 static grn_bool
6886 is_removable_table(grn_ctx *ctx, grn_obj *table, grn_obj *db)
6887 {
6888  grn_bool removable = GRN_TRUE;
6889  grn_id table_id;
6890  char table_name[GRN_TABLE_MAX_KEY_SIZE];
6891  int table_name_size;
6892  grn_table_cursor *cursor;
6893 
6894  table_id = DB_OBJ(table)->id;
6895  table_name_size = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
6896  if ((cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
6897  GRN_CURSOR_BY_ID))) {
6898  grn_id id;
6899  while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
6900  grn_obj *object;
6901 
6902  object = grn_ctx_at(ctx, id);
6903  if (!object) {
6904  ERRCLR(ctx);
6905  continue;
6906  }
6907 
6908  switch (object->header.type) {
6909  case GRN_TABLE_HASH_KEY :
6910  case GRN_TABLE_PAT_KEY :
6911  case GRN_TABLE_DAT_KEY :
6912  if (DB_OBJ(object)->id == table_id) {
6913  break;
6914  }
6915 
6916  if (object->header.domain == table_id) {
6917  char reference_table_name[GRN_TABLE_MAX_KEY_SIZE];
6918  int reference_table_name_size;
6919  reference_table_name_size =
6920  grn_obj_name(ctx, object, reference_table_name,
6923  "[table][remove] a table that references the table exists: "
6924  "<%.*s._key> -> <%.*s>",
6925  reference_table_name_size, reference_table_name,
6926  table_name_size, table_name);
6927  removable = GRN_FALSE;
6928  }
6929  break;
6930  case GRN_COLUMN_VAR_SIZE :
6931  case GRN_COLUMN_FIX_SIZE :
6932  if (object->header.domain == table_id) {
6933  break;
6934  }
6935  if (DB_OBJ(object)->range == table_id) {
6936  char column_name[GRN_TABLE_MAX_KEY_SIZE];
6937  int column_name_size;
6938  column_name_size = grn_obj_name(ctx, object, column_name,
6941  "[table][remove] a column that references the table exists: "
6942  "<%.*s> -> <%.*s>",
6943  column_name_size, column_name,
6944  table_name_size, table_name);
6945  removable = GRN_FALSE;
6946  }
6947  break;
6948  default:
6949  break;
6950  }
6951  grn_obj_unlink(ctx, object);
6952 
6953  if (!removable) {
6954  break;
6955  }
6956  }
6957  grn_table_cursor_close(ctx, cursor);
6958  }
6959 
6960  return removable;
6961 }
6962 
6963 static void
6964 _grn_obj_remove_pat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
6965  const char *path)
6966 {
6967  if (!is_removable_table(ctx, obj, db)) {
6968  return;
6969  }
6970  remove_index(ctx, obj, GRN_HOOK_INSERT);
6971  remove_columns(ctx, obj);
6972  grn_obj_close(ctx, obj);
6973  if (path) {
6974  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
6975  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
6976  grn_pat_remove(ctx, path);
6977  }
6978  grn_obj_touch(ctx, db, NULL);
6979 }
6980 
6981 static void
6982 _grn_obj_remove_dat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
6983  const char *path)
6984 {
6985  if (!is_removable_table(ctx, obj, db)) {
6986  return;
6987  }
6988  remove_index(ctx, obj, GRN_HOOK_INSERT);
6989  remove_columns(ctx, obj);
6990  grn_obj_close(ctx, obj);
6991  if (path) {
6992  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
6993  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
6994  grn_dat_remove(ctx, path);
6995  }
6996  grn_obj_touch(ctx, db, NULL);
6997 }
6998 
6999 static void
7000 _grn_obj_remove_hash(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
7001  const char *path)
7002 {
7003  if (!is_removable_table(ctx, obj, db)) {
7004  return;
7005  }
7006  remove_index(ctx, obj, GRN_HOOK_INSERT);
7007  remove_columns(ctx, obj);
7008  grn_obj_close(ctx, obj);
7009  if (path) {
7010  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
7011  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
7012  grn_hash_remove(ctx, path);
7013  }
7014  grn_obj_touch(ctx, db, NULL);
7015 }
7016 
7017 static void
7018 _grn_obj_remove_array(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
7019  const char *path)
7020 {
7021  if (!is_removable_table(ctx, obj, db)) {
7022  return;
7023  }
7024  remove_columns(ctx, obj);
7025  grn_obj_close(ctx, obj);
7026  if (path) {
7027  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
7028  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
7029  grn_array_remove(ctx, path);
7030  }
7031  grn_obj_touch(ctx, db, NULL);
7032 }
7033 
7034 static void
7035 _grn_obj_remove_ja(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
7036  const char *path)
7037 {
7038  remove_index(ctx, obj, GRN_HOOK_SET);
7039  grn_obj_close(ctx, obj);
7040  if (path) {
7041  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
7042  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
7043  grn_ja_remove(ctx, path);
7044  }
7045  grn_obj_touch(ctx, db, NULL);
7046 }
7047 
7048 static void
7049 _grn_obj_remove_ra(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
7050  const char *path)
7051 {
7052  remove_index(ctx, obj, GRN_HOOK_SET);
7053  grn_obj_close(ctx, obj);
7054  if (path) {
7055  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
7056  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
7057  grn_ra_remove(ctx, path);
7058  }
7059  grn_obj_touch(ctx, db, NULL);
7060 }
7061 
7062 static void
7063 _grn_obj_remove_index(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
7064  const char *path)
7065 {
7066  delete_source_hook(ctx, obj);
7067  grn_obj_close(ctx, obj);
7068  if (path) {
7069  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
7070  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
7071  grn_ii_remove(ctx, path);
7072  }
7073  grn_obj_touch(ctx, db, NULL);
7074 }
7075 
7076 static void
7077 _grn_obj_remove_db_obj(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
7078  const char *path)
7079 {
7080  grn_obj_close(ctx, obj);
7081  if (!(id & GRN_OBJ_TMP_OBJECT)) {
7082  grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
7083  grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
7084  }
7085  if (path) {
7086  grn_io_remove(ctx, path);
7087  }
7088  grn_obj_touch(ctx, db, NULL);
7089 }
7090 
7091 static void
7092 _grn_obj_remove_other(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
7093  const char *path)
7094 {
7095  grn_obj_close(ctx, obj);
7096 }
7097 
7098 static void
7099 _grn_obj_remove(grn_ctx *ctx, grn_obj *obj)
7100 {
7101  grn_id id = GRN_ID_NIL;
7102  grn_obj *db = NULL;
7103  const char *io_path;
7104  char *path;
7105  if (ctx->impl && ctx->impl->db) {
7106  uint32_t s = 0;
7107  const char *n = _grn_table_key(ctx, ctx->impl->db, DB_OBJ(obj)->id, &s);
7108  GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:obj_remove %.*s", s, n);
7109  }
7110  if ((io_path = grn_obj_path(ctx, obj)) && *io_path != '\0') {
7111  if (!(path = GRN_STRDUP(io_path))) {
7112  ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
7113  return;
7114  }
7115  } else {
7116  path = NULL;
7117  }
7118  if (GRN_DB_OBJP(obj)) {
7119  id = DB_OBJ(obj)->id;
7120  db = DB_OBJ(obj)->db;
7121  }
7122  switch (obj->header.type) {
7123  case GRN_DB :
7124  _grn_obj_remove_db(ctx, obj, db, id, path);
7125  break;
7126  case GRN_TABLE_PAT_KEY :
7127  _grn_obj_remove_pat(ctx, obj, db, id, path);
7128  break;
7129  case GRN_TABLE_DAT_KEY :
7130  _grn_obj_remove_dat(ctx, obj, db, id, path);
7131  break;
7132  case GRN_TABLE_HASH_KEY :
7133  _grn_obj_remove_hash(ctx, obj, db, id, path);
7134  break;
7135  case GRN_TABLE_NO_KEY :
7136  _grn_obj_remove_array(ctx, obj, db, id, path);
7137  break;
7138  case GRN_COLUMN_VAR_SIZE :
7139  _grn_obj_remove_ja(ctx, obj, db, id, path);
7140  break;
7141  case GRN_COLUMN_FIX_SIZE :
7142  _grn_obj_remove_ra(ctx, obj, db, id, path);
7143  break;
7144  case GRN_COLUMN_INDEX :
7145  _grn_obj_remove_index(ctx, obj, db, id, path);
7146  break;
7147  default :
7148  if (GRN_DB_OBJP(obj)) {
7149  _grn_obj_remove_db_obj(ctx, obj, db, id, path);
7150  } else {
7151  _grn_obj_remove_other(ctx, obj, db, id, path);
7152  }
7153  }
7154  if (path) { GRN_FREE(path); }
7155 }
7156 
7157 grn_rc
7159 {
7160  GRN_API_ENTER;
7161  if (ctx->impl && ctx->impl->db && ctx->impl->db != obj) {
7162  grn_io *io = grn_obj_io(ctx->impl->db);
7163  if (!grn_io_lock(ctx, io, 10000000)) {
7164  _grn_obj_remove(ctx, obj);
7165  grn_io_unlock(io);
7166  }
7167  } else {
7168  _grn_obj_remove(ctx, obj);
7169  }
7170  GRN_API_RETURN(ctx->rc);
7171 }
7172 
7173 grn_rc
7175  const void *dest_key, unsigned int dest_key_size)
7176 {
7178  GRN_API_ENTER;
7179  if (table->header.type == GRN_TABLE_DAT_KEY) {
7180  grn_dat *dat = (grn_dat *)table;
7181  if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
7182  if (grn_io_lock(ctx, dat->io, 10000000)) {
7183  rc = ctx->rc;
7184  } else {
7185  rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
7186  grn_io_unlock(dat->io);
7187  }
7188  } else {
7189  rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
7190  }
7191  }
7192  GRN_API_RETURN(rc);
7193 }
7194 
7195 grn_rc
7197  const void *src_key, unsigned int src_key_size,
7198  const void *dest_key, unsigned int dest_key_size)
7199 {
7201  GRN_API_ENTER;
7202  if (table->header.type == GRN_TABLE_DAT_KEY) {
7203  rc = grn_dat_update(ctx, (grn_dat *)table,
7204  src_key, src_key_size,
7205  dest_key, dest_key_size);
7206  }
7207  GRN_API_RETURN(rc);
7208 }
7209 
7210 grn_rc
7211 grn_obj_rename(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
7212 {
7214  GRN_API_ENTER;
7215  if (ctx && ctx->impl && GRN_DB_P(ctx->impl->db) && GRN_DB_OBJP(obj) && !IS_TEMP(obj)) {
7216  grn_db *s = (grn_db *)ctx->impl->db;
7217  grn_obj *keys = (grn_obj *)s->keys;
7218  rc = grn_table_update_by_id(ctx, keys, DB_OBJ(obj)->id, name, name_size);
7219  }
7220  GRN_API_RETURN(rc);
7221 }
7222 
7223 grn_rc
7224 grn_table_rename(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
7225 {
7227  grn_hash *cols;
7228 
7229  GRN_API_ENTER;
7230 
7231  if (!GRN_OBJ_TABLEP(table)) {
7232  char table_name[GRN_TABLE_MAX_KEY_SIZE];
7233  int table_name_size;
7234  table_name_size = grn_obj_name(ctx, table, table_name,
7236  rc = GRN_INVALID_ARGUMENT;
7237  ERR(rc,
7238  "[table][rename] isn't table: <%.*s> -> <%.*s>",
7239  table_name_size, table_name,
7240  name_size, name);
7241  goto exit;
7242  }
7243  if (IS_TEMP(table)) {
7244  rc = GRN_INVALID_ARGUMENT;
7245  ERR(rc,
7246  "[table][rename] temporary table doesn't have name: "
7247  "(anonymous) -> <%.*s>",
7248  name_size, name);
7249  goto exit;
7250  }
7251 
7252  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
7254  grn_table_columns(ctx, table, "", 0, (grn_obj *)cols);
7255  if (!(rc = grn_obj_rename(ctx, table, name, name_size))) {
7256  grn_id *key;
7257  char fullname[GRN_TABLE_MAX_KEY_SIZE];
7258  memcpy(fullname, name, name_size);
7259  fullname[name_size] = GRN_DB_DELIMITER;
7260  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
7261  grn_obj *col = grn_ctx_at(ctx, *key);
7262  if (col) {
7263  int colname_len = grn_column_name(ctx, col, fullname + name_size + 1,
7264  GRN_TABLE_MAX_KEY_SIZE - name_size - 1);
7265  if (colname_len) {
7266  if ((rc = grn_obj_rename(ctx, col, fullname,
7267  name_size + 1 + colname_len))) {
7268  break;
7269  }
7270  }
7271  }
7272  });
7273  }
7274  grn_hash_close(ctx, cols);
7275  }
7276 exit:
7277  GRN_API_RETURN(rc);
7278 }
7279 
7280 grn_rc
7281 grn_column_rename(grn_ctx *ctx, grn_obj *column, const char *name, unsigned int name_size)
7282 {
7284  GRN_API_ENTER;
7285  if (GRN_DB_OBJP(column)) {
7286  char fullname[GRN_TABLE_MAX_KEY_SIZE];
7287  grn_db *s = (grn_db *)DB_OBJ(column)->db;
7288  int len = grn_table_get_key(ctx, s->keys, DB_OBJ(column)->header.domain,
7289  fullname, GRN_TABLE_MAX_KEY_SIZE);
7290  if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
7292  "[column][rename] too long column name: required name_size(%d) < %d"
7293  ": <%.*s>.<%.*s>",
7294  name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - len,
7295  len, fullname, name_size, name);
7296  goto exit;
7297  }
7298  fullname[len] = GRN_DB_DELIMITER;
7299  memcpy(fullname + len + 1, name, name_size);
7300  name_size += len + 1;
7301  rc = grn_obj_rename(ctx, column, fullname, name_size);
7302  }
7303 exit :
7304  GRN_API_RETURN(rc);
7305 }
7306 
7307 grn_rc
7308 grn_obj_path_rename(grn_ctx *ctx, const char *old_path, const char *new_path)
7309 {
7310  GRN_API_ENTER;
7312 }
7313 
7314 /* db must be validated by caller */
7315 grn_id
7316 grn_obj_register(grn_ctx *ctx, grn_obj *db, const char *name, unsigned int name_size)
7317 {
7318  grn_id id = GRN_ID_NIL;
7319  if (name && name_size) {
7320  grn_db *s = (grn_db *)db;
7321  int added;
7322  if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
7324  "grn_table_add failed: <%.*s>", name_size, name);
7325  } else if (!added) {
7327  "already used name was assigned: <%.*s>", name_size, name);
7328  id = GRN_ID_NIL;
7329  }
7330  } else if (ctx->impl && ctx->impl->values) {
7331  id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
7332  }
7333  return id;
7334 }
7335 
7336 grn_rc
7338 {
7340  GRN_API_ENTER;
7341  if (id) {
7342  if (id & GRN_OBJ_TMP_OBJECT) {
7343  if (ctx->impl && ctx->impl->values) {
7344  rc = grn_array_delete_by_id(ctx, ctx->impl->values,
7345  id & ~GRN_OBJ_TMP_OBJECT, NULL);
7346  }
7347  } else {
7348  db_value *vp;
7349  grn_db *s = (grn_db *)db;
7350  if ((vp = grn_tiny_array_at(&s->values, id))) {
7351  GRN_ASSERT(!vp->lock);
7352  vp->lock = 0;
7353  vp->ptr = NULL;
7354  vp->done = 0;
7355  }
7356  if (removep) {
7357  switch (s->keys->header.type) {
7358  case GRN_TABLE_PAT_KEY :
7359  rc = grn_pat_delete_by_id(ctx, (grn_pat *)s->keys, id, NULL);
7360  break;
7361  case GRN_TABLE_DAT_KEY :
7362  rc = grn_dat_delete_by_id(ctx, (grn_dat *)s->keys, id, NULL);
7363  break;
7364  }
7365  } else {
7366  rc = GRN_SUCCESS;
7367  }
7368  }
7369  }
7370  GRN_API_RETURN(rc);
7371 }
7372 
7373 
7374 grn_rc
7375 grn_obj_path_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, char *buffer)
7376 {
7377  grn_rc rc = GRN_SUCCESS;
7378  GRN_API_ENTER;
7379  if (!GRN_DB_P(db) || !buffer) {
7380  rc = GRN_INVALID_ARGUMENT;
7381  } else {
7382  gen_pathname(grn_obj_io(db)->path, buffer, id);
7383  }
7384  GRN_API_RETURN(rc);
7385 }
7386 
7387 /* db must be validated by caller */
7388 grn_rc
7390 {
7391  grn_rc rc = GRN_SUCCESS;
7392  if (id) {
7393  if (id & GRN_OBJ_TMP_OBJECT) {
7394  if (ctx->impl && ctx->impl->values) {
7395  rc = grn_array_set_value(ctx, ctx->impl->values,
7396  id & ~GRN_OBJ_TMP_OBJECT, &obj, GRN_OBJ_SET);
7397  }
7398  } else {
7399  db_value *vp;
7400  vp = grn_tiny_array_at(&((grn_db *)db)->values, id);
7401  if (!vp) {
7403  ERR(rc, "grn_tiny_array_at failed (%d)", id);
7404  return rc;
7405  }
7406  vp->lock = 1;
7407  vp->ptr = (grn_obj *)obj;
7408  }
7409  }
7410  obj->id = id;
7411  obj->db = db;
7412  obj->source = NULL;
7413  obj->source_size = 0;
7414  {
7415  grn_hook_entry entry;
7416  for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
7417  obj->hooks[entry] = NULL;
7418  }
7419  }
7420  grn_obj_spec_save(ctx, obj);
7421  return rc;
7422 }
7423 
7424 #define GET_PATH(spec,buffer,s,id) do {\
7425  if (spec->header.flags & GRN_OBJ_CUSTOM_NAME) {\
7426  const char *path;\
7427  unsigned int size = grn_vector_get_element(ctx, &v, 1, &path, NULL, NULL); \
7428  if (size > PATH_MAX) { ERR(GRN_FILENAME_TOO_LONG, "too long path"); }\
7429  memcpy(buffer, path, size);\
7430  buffer[size] = '\0';\
7431  } else {\
7432  gen_pathname(grn_obj_io(s->keys)->path, buffer, id); \
7433  }\
7434 } while (0)
7435 
7436 #define UNPACK_INFO() do {\
7437  if (vp->ptr) {\
7438  grn_db_obj *r = DB_OBJ(vp->ptr);\
7439  r->header = spec->header;\
7440  r->id = id;\
7441  r->range = spec->range;\
7442  r->db = (grn_obj *)s;\
7443  size = grn_vector_get_element(ctx, &v, 2, &p, NULL, NULL);\
7444  if (size) {\
7445  if ((r->source = GRN_MALLOC(size))) {\
7446  memcpy(r->source, p, size);\
7447  r->source_size = size;\
7448  }\
7449  }\
7450  size = grn_vector_get_element(ctx, &v, 3, &p, NULL, NULL);\
7451  grn_hook_unpack(ctx, r, p, size);\
7452  }\
7453 } while (0)
7454 
7455 grn_obj *
7457 {
7458  grn_obj *res = NULL;
7459  if (!ctx || !ctx->impl || !id) { return res; }
7460  GRN_API_ENTER;
7461  if (id & GRN_OBJ_TMP_OBJECT) {
7462  if (ctx->impl->values) {
7463  grn_obj **tmp_obj;
7464  tmp_obj = _grn_array_get_value(ctx, ctx->impl->values, id & ~GRN_OBJ_TMP_OBJECT);
7465  if (tmp_obj) {
7466  res = *tmp_obj;
7467  }
7468  }
7469  } else {
7470  grn_db *s = (grn_db *)ctx->impl->db;
7471  if (s) {
7472  db_value *vp;
7473  uint32_t l, *pl, ntrial;
7474  if (!(vp = grn_tiny_array_at(&s->values, id))) { goto exit; }
7475 #ifdef USE_NREF
7476  pl = &vp->lock;
7477  for (ntrial = 0;; ntrial++) {
7478  GRN_ATOMIC_ADD_EX(pl, 1, l);
7479  if (l < GRN_IO_MAX_REF) { break; }
7480  if (ntrial >= 10) {
7481  GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
7482  break;
7483  }
7484  GRN_ATOMIC_ADD_EX(pl, -1, l);
7485  GRN_FUTEX_WAIT(pl);
7486  }
7487 #endif /* USE_NREF */
7488  if (s->specs && !vp->ptr /* && !vp->done */) {
7489 #ifndef USE_NREF
7490  pl = &vp->lock;
7491  for (ntrial = 0;; ntrial++) {
7492  GRN_ATOMIC_ADD_EX(pl, 1, l);
7493  if (l < GRN_IO_MAX_REF) { break; }
7494  if (ntrial >= 10) {
7495  GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
7496  break;
7497  }
7498  GRN_ATOMIC_ADD_EX(pl, -1, l);
7499  GRN_FUTEX_WAIT(pl);
7500  }
7501 #endif /* USE_NREF */
7502  if (!l) {
7503  grn_io_win jw;
7504  uint32_t value_len;
7505  char *value = grn_ja_ref(ctx, s->specs, id, &jw, &value_len);
7506  if (value) {
7507  grn_obj v;
7509  if (!grn_vector_decode(ctx, &v, value, value_len)) {
7510  const char *p;
7511  uint32_t size;
7512  grn_obj_spec *spec;
7513  char buffer[PATH_MAX];
7514  size = grn_vector_get_element(ctx, &v, 0, (const char **)&spec, NULL, NULL);
7515  if (size) {
7516  switch (spec->header.type) {
7517  case GRN_TYPE :
7518  vp->ptr = (grn_obj *)grn_type_open(ctx, spec);
7519  UNPACK_INFO();
7520  break;
7521  case GRN_TABLE_HASH_KEY :
7522  GET_PATH(spec, buffer, s, id);
7523  vp->ptr = (grn_obj *)grn_hash_open(ctx, buffer);
7524  if (vp->ptr) {
7525  grn_obj_flags flags = vp->ptr->header.flags;
7526  UNPACK_INFO();
7527  vp->ptr->header.flags = flags;
7528  }
7529  break;
7530  case GRN_TABLE_PAT_KEY :
7531  GET_PATH(spec, buffer, s, id);
7532  vp->ptr = (grn_obj *)grn_pat_open(ctx, buffer);
7533  if (vp->ptr) {
7534  grn_obj_flags flags = vp->ptr->header.flags;
7535  UNPACK_INFO();
7536  vp->ptr->header.flags = flags;
7537  }
7538  break;
7539  case GRN_TABLE_DAT_KEY :
7540  GET_PATH(spec, buffer, s, id);
7541  vp->ptr = (grn_obj *)grn_dat_open(ctx, buffer);
7542  if (vp->ptr) {
7543  grn_obj_flags flags = vp->ptr->header.flags;
7544  UNPACK_INFO();
7545  vp->ptr->header.flags = flags;
7546  }
7547  break;
7548  case GRN_TABLE_NO_KEY :
7549  GET_PATH(spec, buffer, s, id);
7550  vp->ptr = (grn_obj *)grn_array_open(ctx, buffer);
7551  UNPACK_INFO();
7552  break;
7553  case GRN_COLUMN_VAR_SIZE :
7554  GET_PATH(spec, buffer, s, id);
7555  vp->ptr = (grn_obj *)grn_ja_open(ctx, buffer);
7556  UNPACK_INFO();
7557  break;
7558  case GRN_COLUMN_FIX_SIZE :
7559  GET_PATH(spec, buffer, s, id);
7560  vp->ptr = (grn_obj *)grn_ra_open(ctx, buffer);
7561  UNPACK_INFO();
7562  break;
7563  case GRN_COLUMN_INDEX :
7564  GET_PATH(spec, buffer, s, id);
7565  {
7566  grn_obj *table = grn_ctx_at(ctx, spec->header.domain);
7567  vp->ptr = (grn_obj *)grn_ii_open(ctx, buffer, table);
7568  }
7569  UNPACK_INFO();
7570  break;
7571  case GRN_PROC :
7572  GET_PATH(spec, buffer, s, id);
7573  grn_plugin_register(ctx, buffer);
7574  break;
7575  case GRN_EXPR :
7576  {
7577  uint8_t *u;
7578  size = grn_vector_get_element(ctx, &v, 4, &p, NULL, NULL);
7579  u = (uint8_t *)p;
7580  vp->ptr = grn_expr_open(ctx, spec, u, u + size);
7581  }
7582  break;
7583  }
7584  }
7585  grn_obj_close(ctx, &v);
7586  }
7587  grn_ja_unref(ctx, &jw);
7588  }
7589 #ifndef USE_NREF
7590  GRN_ATOMIC_ADD_EX(pl, -1, l);
7591 #endif /* USE_NREF */
7592  vp->done = 1;
7593  GRN_FUTEX_WAKE(&vp->ptr);
7594  } else {
7595  for (ntrial = 0; !vp->ptr; ntrial++) {
7596  if (ntrial >= 1000) {
7597  GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%d,%p,%d)!", id, vp->ptr, vp->lock);
7598  break;
7599  }
7600  GRN_FUTEX_WAIT(&vp->ptr);
7601  }
7602  }
7603  }
7604  res = vp->ptr;
7605  }
7606  }
7607 exit :
7608  GRN_API_RETURN(res);
7609 }
7610 
7611 grn_obj *
7612 grn_obj_open(grn_ctx *ctx, unsigned char type, grn_obj_flags flags, grn_id domain)
7613 {
7614  grn_obj *obj = GRN_MALLOCN(grn_obj, 1);
7615  if (obj) {
7616  GRN_OBJ_INIT(obj, type, flags, domain);
7618  }
7619  return obj;
7620 }
7621 
7622 grn_obj *
7624 {
7625  grn_obj *new = grn_obj_open(ctx, obj->header.type, obj->header.impl_flags, obj->header.domain);
7626  if (new) {
7627  /* todo : deep copy if (obj->header.impl_flags & GRN_OBJ_DO_SHALLOW_COPY) */
7628  new->u.b.head = obj->u.b.head;
7629  new->u.b.curr = obj->u.b.curr;
7630  new->u.b.tail = obj->u.b.tail;
7631  obj->u.b.head = NULL;
7632  obj->u.b.curr = NULL;
7633  obj->u.b.tail = NULL;
7634  }
7635  return new;
7636 }
7637 
7638 grn_rc
7640 {
7642  GRN_API_ENTER;
7643  if (obj) {
7644  if (GRN_DB_OBJP(obj)) {
7645  grn_hook_entry entry;
7646  if (DB_OBJ(obj)->finalizer) {
7647  DB_OBJ(obj)->finalizer(ctx, 1, &obj, &DB_OBJ(obj)->user_data);
7648  }
7649  if (DB_OBJ(obj)->source) {
7650  GRN_FREE(DB_OBJ(obj)->source);
7651  }
7652  for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
7653  grn_hook_free(ctx, DB_OBJ(obj)->hooks[entry]);
7654  }
7655  grn_obj_delete_by_id(ctx, DB_OBJ(obj)->db, DB_OBJ(obj)->id, GRN_FALSE);
7656  }
7657  switch (obj->header.type) {
7658  case GRN_VECTOR :
7659  if (obj->u.v.body && !(obj->header.impl_flags & GRN_OBJ_REFER)) {
7660  grn_obj_close(ctx, obj->u.v.body);
7661  }
7662  if (obj->u.v.sections) { GRN_FREE(obj->u.v.sections); }
7663  if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
7664  rc = GRN_SUCCESS;
7665  break;
7666  case GRN_VOID :
7667  case GRN_BULK :
7668  case GRN_PTR :
7669  case GRN_UVECTOR :
7670  case GRN_PVECTOR :
7671  case GRN_MSG :
7672  obj->header.type = GRN_VOID;
7673  rc = grn_bulk_fin(ctx, obj);
7674  if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
7675  break;
7676  case GRN_ACCESSOR :
7677  {
7678  grn_accessor *p, *n;
7679  for (p = (grn_accessor *)obj; p; p = n) {
7680  n = p->next;
7681  GRN_FREE(p);
7682  }
7683  }
7684  rc = GRN_SUCCESS;
7685  break;
7686  case GRN_SNIP :
7687  rc = grn_snip_close_real(ctx, (grn_snip *)obj);
7688  break;
7689  case GRN_STRING :
7690  rc = grn_string_close(ctx, obj);
7691  break;
7693  grn_pat_cursor_close(ctx, (grn_pat_cursor *)obj);
7694  break;
7696  grn_dat_cursor_close(ctx, (grn_dat_cursor *)obj);
7697  break;
7700  break;
7703  break;
7705  {
7706  grn_index_cursor *ic = (grn_index_cursor *)obj;
7707  if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
7708  GRN_FREE(ic);
7709  }
7710  break;
7712  grn_geo_cursor_close(ctx, obj);
7713  break;
7714  case GRN_TYPE :
7715  GRN_FREE(obj);
7716  rc = GRN_SUCCESS;
7717  break;
7718  case GRN_DB :
7719  rc = grn_db_close(ctx, obj);
7720  break;
7721  case GRN_TABLE_PAT_KEY :
7722  rc = grn_pat_close(ctx, (grn_pat *)obj);
7723  break;
7724  case GRN_TABLE_DAT_KEY :
7725  rc = grn_dat_close(ctx, (grn_dat *)obj);
7726  break;
7727  case GRN_TABLE_HASH_KEY :
7728  rc = grn_hash_close(ctx, (grn_hash *)obj);
7729  break;
7730  case GRN_TABLE_NO_KEY :
7731  rc = grn_array_close(ctx, (grn_array *)obj);
7732  break;
7733  case GRN_COLUMN_VAR_SIZE :
7734  rc = grn_ja_close(ctx, (grn_ja *)obj);
7735  break;
7736  case GRN_COLUMN_FIX_SIZE :
7737  rc = grn_ra_close(ctx, (grn_ra *)obj);
7738  break;
7739  case GRN_COLUMN_INDEX :
7740  rc = grn_ii_close(ctx, (grn_ii *)obj);
7741  break;
7742  case GRN_PROC :
7743  {
7744  uint32_t i;
7745  grn_proc *p = (grn_proc *)obj;
7746  /*
7747  if (obj->header.domain) {
7748  grn_hash_delete(ctx, ctx->impl->qe, &obj->header.domain, sizeof(grn_id), NULL);
7749  }
7750  */
7751  for (i = 0; i < p->nvars; i++) {
7752  grn_obj_close(ctx, &p->vars[i].value);
7753  }
7754  GRN_REALLOC(p->vars, 0);
7755  grn_obj_close(ctx, &p->name_buf);
7756  if (p->obj.range != GRN_ID_NIL) {
7757  grn_plugin_close(ctx, p->obj.range);
7758  }
7759  GRN_FREE(obj);
7760  rc = GRN_SUCCESS;
7761  }
7762  break;
7763  case GRN_EXPR :
7764  rc = grn_expr_close(ctx, obj);
7765  break;
7766  }
7767  }
7768  GRN_API_RETURN(rc);
7769 }
7770 
7771 void
7773 {
7774  if (obj &&
7775  (!GRN_DB_OBJP(obj) ||
7776  (((grn_db_obj *)obj)->id & GRN_OBJ_TMP_OBJECT) ||
7777  (((grn_db_obj *)obj)->id == GRN_ID_NIL) ||
7778  obj->header.type == GRN_DB)) {
7779  grn_obj_close(ctx, obj);
7780  } else if (GRN_DB_OBJP(obj)) {
7781 #ifdef USE_NREF
7782  grn_db_obj *dob = DB_OBJ(obj);
7783  grn_db *s = (grn_db *)dob->db;
7784  db_value *vp = grn_tiny_array_at(&s->values, dob->id);
7785  if (vp) {
7786  uint32_t l, *pl = &vp->lock;
7787  if (!vp->lock) {
7788  GRN_LOG(ctx, GRN_LOG_ERROR, "invalid unlink(%p,%d)", obj, vp->lock);
7789  return;
7790  }
7791  GRN_ATOMIC_ADD_EX(pl, -1, l);
7792  if (l == 1) {
7793  GRN_ATOMIC_ADD_EX(pl, GRN_IO_MAX_REF, l);
7794  if (l == GRN_IO_MAX_REF) {
7795 #ifdef CALL_FINALIZER
7796  grn_obj_close(ctx, obj);
7797  vp->done = 0;
7798  if (dob->finalizer) {
7799  dob->finalizer(ctx, 1, &obj, &dob->user_data);
7800  dob->finalizer = NULL;
7801  dob->user_data.ptr = NULL;
7802  }
7803 #endif /* CALL_FINALIZER */
7804  }
7805  GRN_ATOMIC_ADD_EX(pl, -GRN_IO_MAX_REF, l);
7806  GRN_FUTEX_WAKE(pl);
7807  }
7808  }
7809 #endif /* USE_NREF */
7810  }
7811 }
7812 
7813 #define VECTOR_CLEAR(ctx,obj) do {\
7814  if ((obj)->u.v.body && !((obj)->header.impl_flags & GRN_OBJ_REFER)) {\
7815  grn_obj_close((ctx), (obj)->u.v.body);\
7816  }\
7817  if ((obj)->u.v.sections) { GRN_FREE((obj)->u.v.sections); }\
7818  (obj)->header.impl_flags &= ~GRN_OBJ_DO_SHALLOW_COPY;\
7819  (obj)->u.b.head = NULL;\
7820  (obj)->u.b.curr = NULL;\
7821  (obj)->u.b.tail = NULL;\
7822 } while (0)
7823 
7824 static void
7825 grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj)
7826 {
7827  if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
7828  obj->header.type = GRN_VECTOR;
7829 }
7830 
7831 static void
7832 grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj)
7833 {
7834  if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
7835  obj->header.type = GRN_BULK;
7836 }
7837 
7838 grn_rc
7839 grn_obj_reinit(grn_ctx *ctx, grn_obj *obj, grn_id domain, unsigned char flags)
7840 {
7841  if (!GRN_OBJ_MUTABLE(obj)) {
7842  ERR(GRN_INVALID_ARGUMENT, "invalid obj assigned");
7843  } else {
7844  switch (domain) {
7845  case GRN_DB_VOID :
7846  if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
7847  obj->header.type = GRN_VOID;
7848  obj->header.domain = domain;
7849  GRN_BULK_REWIND(obj);
7850  break;
7851  case GRN_DB_OBJECT :
7852  case GRN_DB_BOOL :
7853  case GRN_DB_INT8 :
7854  case GRN_DB_UINT8 :
7855  case GRN_DB_INT16 :
7856  case GRN_DB_UINT16 :
7857  case GRN_DB_INT32 :
7858  case GRN_DB_UINT32 :
7859  case GRN_DB_INT64 :
7860  case GRN_DB_UINT64 :
7861  case GRN_DB_FLOAT :
7862  case GRN_DB_TIME :
7863  case GRN_DB_TOKYO_GEO_POINT :
7864  case GRN_DB_WGS84_GEO_POINT :
7865  if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
7866  obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
7867  obj->header.domain = domain;
7868  GRN_BULK_REWIND(obj);
7869  break;
7870  case GRN_DB_SHORT_TEXT :
7871  case GRN_DB_TEXT :
7872  case GRN_DB_LONG_TEXT :
7873  if (flags & GRN_OBJ_VECTOR) {
7874  if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
7875  obj->header.type = GRN_VECTOR;
7876  if (obj->u.v.body) {
7877  grn_obj_reinit(ctx, obj->u.v.body, domain, 0);
7878  }
7879  obj->u.v.n_sections = 0;
7880  } else {
7881  if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
7882  obj->header.type = GRN_BULK;
7883  }
7884  obj->header.domain = domain;
7885  GRN_BULK_REWIND(obj);
7886  break;
7887  default :
7888  {
7889  grn_obj *d = grn_ctx_at(ctx, domain);
7890  if (!d) {
7891  ERR(GRN_INVALID_ARGUMENT, "invalid domain assigned");
7892  } else {
7893  if (d->header.type == GRN_TYPE && (d->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
7894  if (flags & GRN_OBJ_VECTOR) {
7895  if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
7896  obj->header.type = GRN_VECTOR;
7897  } else {
7898  if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
7899  obj->header.type = GRN_BULK;
7900  }
7901  } else {
7902  if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
7903  obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
7904  }
7905  obj->header.domain = domain;
7906  GRN_BULK_REWIND(obj);
7907  }
7908  }
7909  break;
7910  }
7911  }
7912  return ctx->rc;
7913 }
7914 
7915 grn_rc
7916 grn_obj_reinit_for(grn_ctx *ctx, grn_obj *obj, grn_obj *domain_obj)
7917 {
7918  grn_id domain = GRN_ID_NIL;
7919  grn_obj_flags flags = 0;
7920 
7921  if (!GRN_DB_OBJP(domain_obj) && domain_obj->header.type != GRN_ACCESSOR) {
7922  grn_obj inspected;
7923  GRN_TEXT_INIT(&inspected, 0);
7924  limited_size_inspect(ctx, &inspected, domain_obj);
7926  "[reinit] invalid domain object: <%.*s>",
7927  (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
7928  GRN_OBJ_FIN(ctx, &inspected);
7929  return ctx->rc;
7930  }
7931 
7932  grn_obj_get_range_info(ctx, domain_obj, &domain, &flags);
7933  if (GRN_OBJ_TABLEP(domain_obj) &&
7934  domain_obj->header.type != GRN_TABLE_NO_KEY) {
7935  domain = domain_obj->header.domain;
7936  }
7937  return grn_obj_reinit(ctx, obj, domain, flags);
7938 }
7939 
7940 const char *
7942 {
7943  grn_io *io;
7944  const char *path = NULL;
7945  GRN_API_ENTER;
7946  if (obj->header.type == GRN_PROC) {
7947  path = grn_plugin_path(ctx, DB_OBJ(obj)->range);
7948  GRN_API_RETURN(path);
7949  }
7950  io = grn_obj_io(obj);
7951  if (io && !(io->flags & GRN_IO_TEMPORARY)) { path = io->path; }
7952  GRN_API_RETURN(path);
7953 }
7954 
7955 int
7956 grn_obj_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
7957 {
7958  int len = 0;
7959  GRN_API_ENTER;
7960  if (GRN_DB_OBJP(obj)) {
7961  if (DB_OBJ(obj)->id) {
7962  grn_db *s = (grn_db *)DB_OBJ(obj)->db;
7963  if (!(DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)) {
7964  len = grn_table_get_key(ctx, s->keys, DB_OBJ(obj)->id, namebuf, buf_size);
7965  }
7966  }
7967  }
7968  GRN_API_RETURN(len);
7969 }
7970 
7971 int
7972 grn_column_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
7973 {
7974  int len = 0;
7975  char buf[GRN_TABLE_MAX_KEY_SIZE];
7976  if (!obj) { return len; }
7977  GRN_API_ENTER;
7978  if (GRN_DB_OBJP(obj)) {
7979  if (DB_OBJ(obj)->id && DB_OBJ(obj)->id < GRN_ID_MAX) {
7980  grn_db *s = (grn_db *)DB_OBJ(obj)->db;
7981  len = grn_table_get_key(ctx, s->keys, DB_OBJ(obj)->id, buf, GRN_TABLE_MAX_KEY_SIZE);
7982  if (len) {
7983  int cl;
7984  char *p = buf, *p0 = p, *pe = p + len;
7985  for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
7986  if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
7987  }
7988  len = pe - p0;
7989  if (len && len <= buf_size) {
7990  memcpy(namebuf, p0, len);
7991  }
7992  }
7993  }
7994  } else if (obj->header.type == GRN_ACCESSOR) {
7995  const char *name = NULL;
7996  grn_accessor *a;
7997  for (a = (grn_accessor *)obj; a; a = a->next) {
7998  switch (a->action) {
7999  case GRN_ACCESSOR_GET_ID :
8000  name = "_id";
8001  break;
8002  case GRN_ACCESSOR_GET_KEY :
8003  name = "_key";
8004  break;
8005  case GRN_ACCESSOR_GET_VALUE :
8006  name = "_value";
8007  break;
8008  case GRN_ACCESSOR_GET_SCORE :
8009  name = "_score";
8010  break;
8012  name = "_nsubrecs";
8013  break;
8016  case GRN_ACCESSOR_LOOKUP :
8017  case GRN_ACCESSOR_FUNCALL :
8018  break;
8019  }
8020  }
8021  if (name) {
8022  len = strlen(name);
8023  if (len <= buf_size) {
8024  memcpy(namebuf, name, len);
8025  }
8026  }
8027  }
8028  GRN_API_RETURN(len);
8029 }
8030 
8031 grn_rc
8033 {
8034  if (GRN_DB_OBJP(obj)) {
8035  if (DB_OBJ(obj)->id && DB_OBJ(obj)->id < GRN_ID_MAX) {
8036  uint32_t len;
8037  grn_db *s = (grn_db *)DB_OBJ(obj)->db;
8038  const char *p = _grn_table_key(ctx, s->keys, DB_OBJ(obj)->id, &len);
8039  if (len) {
8040  int cl;
8041  const char *p0 = p, *pe = p + len;
8042  for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
8043  if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
8044  }
8045  GRN_TEXT_PUT(ctx, buf, p0, pe - p0);
8046  }
8047  }
8048  } else if (obj->header.type == GRN_ACCESSOR) {
8049  grn_accessor *a;
8050  for (a = (grn_accessor *)obj; a; a = a->next) {
8051  switch (a->action) {
8052  case GRN_ACCESSOR_GET_ID :
8053  GRN_TEXT_PUTS(ctx, buf, "_id");
8054  break;
8055  case GRN_ACCESSOR_GET_KEY :
8056  if (!a->next) {
8057  GRN_TEXT_PUTS(ctx, buf, "_key");
8058  }
8059  break;
8060  case GRN_ACCESSOR_GET_VALUE :
8061  if (!a->next) {
8062  GRN_TEXT_PUTS(ctx, buf, "_value");
8063  }
8064  break;
8065  case GRN_ACCESSOR_GET_SCORE :
8066  GRN_TEXT_PUTS(ctx, buf, "_score");
8067  break;
8069  GRN_TEXT_PUTS(ctx, buf, "_nsubrecs");
8070  break;
8072  grn_column_name_(ctx, a->obj, buf);
8073  if (a->next) { GRN_TEXT_PUTC(ctx, buf, '.'); }
8074  break;
8076  case GRN_ACCESSOR_LOOKUP :
8077  case GRN_ACCESSOR_FUNCALL :
8078  break;
8079  }
8080  }
8081  }
8082  return ctx->rc;
8083 }
8084 
8085 int
8086 grn_obj_expire(grn_ctx *ctx, grn_obj *obj, int threshold)
8087 {
8088  GRN_API_ENTER;
8089  GRN_API_RETURN(0);
8090 }
8091 
8092 int
8094 {
8095  GRN_API_ENTER;
8096  GRN_API_RETURN(0);
8097 }
8098 
8099 grn_rc
8100 grn_obj_lock(grn_ctx *ctx, grn_obj *obj, grn_id id, int timeout)
8101 {
8102  grn_rc rc = GRN_SUCCESS;
8103  GRN_API_ENTER;
8104  rc = grn_io_lock(ctx, grn_obj_io(obj), timeout);
8105  GRN_API_RETURN(rc);
8106 }
8107 
8108 grn_rc
8110 {
8111  GRN_API_ENTER;
8112  grn_io_unlock(grn_obj_io(obj));
8114 }
8115 
8116 grn_user_data *
8118 {
8119  if (!GRN_DB_OBJP(obj)) { return NULL; }
8120  return &DB_OBJ(obj)->user_data;
8121 }
8122 
8123 grn_rc
8125 {
8126  if (!GRN_DB_OBJP(obj)) { return GRN_INVALID_ARGUMENT; }
8127  DB_OBJ(obj)->finalizer = func;
8128  return GRN_SUCCESS;
8129 }
8130 
8131 grn_rc
8133 {
8134  GRN_API_ENTER;
8135  switch (obj->header.type) {
8136  case GRN_DB:
8137  {
8138  grn_table_cursor *cur;
8139  if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
8140  grn_id id;
8141  while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
8142  grn_obj *tbl = grn_ctx_at(ctx, id);
8143  if (tbl) {
8144  switch (tbl->header.type) {
8145  case GRN_TABLE_HASH_KEY :
8146  case GRN_TABLE_PAT_KEY:
8147  case GRN_TABLE_DAT_KEY:
8148  case GRN_TABLE_NO_KEY:
8149  grn_obj_clear_lock(ctx, tbl);
8150  }
8151  } else {
8152  if (ctx->rc != GRN_SUCCESS) {
8153  ERRCLR(ctx);
8154  }
8155  }
8156  }
8157  grn_table_cursor_close(ctx, cur);
8158  }
8159  }
8160  grn_io_clear_lock(grn_obj_io(obj));
8161  break;
8162  case GRN_TABLE_NO_KEY :
8164  /* fallthru */
8165  case GRN_TABLE_HASH_KEY :
8166  case GRN_TABLE_PAT_KEY :
8167  case GRN_TABLE_DAT_KEY :
8168  {
8169  grn_hash *cols;
8170  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
8172  if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
8173  grn_id *key;
8174  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
8175  grn_obj *col = grn_ctx_at(ctx, *key);
8176  if (col) { grn_obj_clear_lock(ctx, col); }
8177  });
8178  }
8179  grn_hash_close(ctx, cols);
8180  }
8181  grn_io_clear_lock(grn_obj_io(obj));
8182  }
8183  break;
8184  case GRN_COLUMN_FIX_SIZE:
8185  case GRN_COLUMN_VAR_SIZE:
8186  case GRN_COLUMN_INDEX:
8187  grn_io_clear_lock(grn_obj_io(obj));
8188  break;
8189  }
8191 }
8192 
8193 unsigned int
8195 {
8196  unsigned int res = 0;
8197  GRN_API_ENTER;
8198  res = grn_io_is_locked(grn_obj_io(obj));
8199  GRN_API_RETURN(res);
8200 }
8201 
8202 grn_obj *
8204 {
8205  grn_obj *db = NULL;
8206  GRN_API_ENTER;
8207  if (GRN_DB_OBJP(obj)) { db = DB_OBJ(obj)->db; }
8208  GRN_API_RETURN(db);
8209 }
8210 
8211 grn_id
8213 {
8214  grn_id id = GRN_ID_NIL;
8215  GRN_API_ENTER;
8216  if (GRN_DB_OBJP(obj)) {
8217  id = DB_OBJ(obj)->id;
8218  }
8219  GRN_API_RETURN(id);
8220 }
8221 
8222 int
8223 grn_obj_defrag(grn_ctx *ctx, grn_obj *obj, int threshold)
8224 {
8225  int r = 0;
8226  GRN_API_ENTER;
8227  switch (obj->header.type) {
8228  case GRN_DB:
8229  {
8230  grn_table_cursor *cur;
8231  if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
8232  grn_id id;
8233  while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
8234  grn_obj *ja = grn_ctx_at(ctx, id);
8235  if (ja && ja->header.type == GRN_COLUMN_VAR_SIZE) {
8236  r += grn_ja_defrag(ctx, (grn_ja *)ja, threshold);
8237  }
8238  }
8239  grn_table_cursor_close(ctx, cur);
8240  }
8241  }
8242  break;
8243  case GRN_TABLE_HASH_KEY :
8244  case GRN_TABLE_PAT_KEY :
8245  case GRN_TABLE_DAT_KEY :
8246  case GRN_TABLE_NO_KEY :
8247  {
8248  grn_hash *cols;
8249  if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
8251  if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
8252  grn_id *key;
8253  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
8254  grn_obj *col = grn_ctx_at(ctx, *key);
8255  if (col) {
8256  r += grn_obj_defrag(ctx, col, threshold);
8257  grn_obj_unlink(ctx, col);
8258  }
8259  });
8260  }
8261  grn_hash_close(ctx, cols);
8262  }
8263  }
8264  break;
8265  case GRN_COLUMN_VAR_SIZE:
8266  r = grn_ja_defrag(ctx, (grn_ja *)obj, threshold);
8267  break;
8268  }
8269  GRN_API_RETURN(r);
8270 }
8271 
8272 /**** sort ****/
8273 
8274 typedef struct {
8276  uint32_t size;
8277  const void *value;
8278 } sort_entry;
8279 
8280 enum {
8281  KEY_ID = 0,
8293 };
8294 
8295 #define CMPNUM(type) do {\
8296  if (as) {\
8297  if (bs) {\
8298  type va = *((type *)(ap));\
8299  type vb = *((type *)(bp));\
8300  if (va != vb) { return va > vb; }\
8301  } else {\
8302  return 1;\
8303  }\
8304  } else {\
8305  if (bs) { return 0; }\
8306  }\
8307 } while (0)
8308 
8309 inline static int
8310 compare_value(grn_ctx *ctx, sort_entry *a, sort_entry *b,
8311  grn_table_sort_key *keys, int n_keys)
8312 {
8313  int i;
8314  uint8_t type;
8315  uint32_t as, bs;
8316  const unsigned char *ap, *bp;
8317  for (i = 0; i < n_keys; i++, keys++) {
8318  if (i) {
8319  const char *ap_raw, *bp_raw;
8320  if (keys->flags & GRN_TABLE_SORT_DESC) {
8321  ap_raw = grn_obj_get_value_(ctx, keys->key, b->id, &as);
8322  bp_raw = grn_obj_get_value_(ctx, keys->key, a->id, &bs);
8323  } else {
8324  ap_raw = grn_obj_get_value_(ctx, keys->key, a->id, &as);
8325  bp_raw = grn_obj_get_value_(ctx, keys->key, b->id, &bs);
8326  }
8327  ap = (const unsigned char *)ap_raw;
8328  bp = (const unsigned char *)bp_raw;
8329  } else {
8330  if (keys->flags & GRN_TABLE_SORT_DESC) {
8331  ap = b->value; as = b->size;
8332  bp = a->value; bs = a->size;
8333  } else {
8334  ap = a->value; as = a->size;
8335  bp = b->value; bs = b->size;
8336  }
8337  }
8338  type = keys->offset;
8339  switch (type) {
8340  case KEY_ID :
8341  if (ap != bp) { return ap > bp; }
8342  break;
8343  case KEY_BULK :
8344  for (;; ap++, bp++, as--, bs--) {
8345  if (!as) { if (bs) { return 0; } else { break; } }
8346  if (!bs) { return 1; }
8347  if (*ap < *bp) { return 0; }
8348  if (*ap > *bp) { return 1; }
8349  }
8350  break;
8351  case KEY_INT8 :
8352  CMPNUM(int8_t);
8353  break;
8354  case KEY_INT16 :
8355  CMPNUM(int16_t);
8356  break;
8357  case KEY_INT32 :
8358  CMPNUM(int32_t);
8359  break;
8360  case KEY_INT64 :
8361  CMPNUM(int64_t);
8362  break;
8363  case KEY_UINT8 :
8364  CMPNUM(uint8_t);
8365  break;
8366  case KEY_UINT16 :
8367  CMPNUM(uint16_t);
8368  break;
8369  case KEY_UINT32 :
8370  CMPNUM(uint32_t);
8371  break;
8372  case KEY_UINT64 :
8373  CMPNUM(uint64_t);
8374  break;
8375  case KEY_FLOAT32 :
8376  if (as) {
8377  if (bs) {
8378  float va = *((float *)(ap));
8379  float vb = *((float *)(bp));
8380  if (va < vb || va > vb) { return va > vb; }
8381  } else {
8382  return 1;
8383  }
8384  } else {
8385  if (bs) { return 0; }
8386  }
8387  break;
8388  case KEY_FLOAT64 :
8389  if (as) {
8390  if (bs) {
8391  double va = *((double *)(ap));
8392  double vb = *((double *)(bp));
8393  if (va < vb || va > vb) { return va > vb; }
8394  } else {
8395  return 1;
8396  }
8397  } else {
8398  if (bs) { return 0; }
8399  }
8400  break;
8401  }
8402  }
8403  return 0;
8404 }
8405 
8406 inline static void
8407 swap(sort_entry *a, sort_entry *b)
8408 {
8409  sort_entry c_ = *a;
8410  *a = *b;
8411  *b = c_;
8412 }
8413 
8414 inline static sort_entry *
8415 part(grn_ctx *ctx, sort_entry *b, sort_entry *e, grn_table_sort_key *keys, int n_keys)
8416 {
8417  sort_entry *c;
8418  intptr_t d = e - b;
8419  if (compare_value(ctx, b, e, keys, n_keys)) {
8420  swap(b, e);
8421  }
8422  if (d < 2) { return NULL; }
8423  c = b + (d >> 1);
8424  if (compare_value(ctx, b, c, keys, n_keys)) {
8425  swap(b, c);
8426  } else {
8427  if (compare_value(ctx, c, e, keys, n_keys)) {
8428  swap(c, e);
8429  }
8430  }
8431  if (d < 3) { return NULL; }
8432  b++;
8433  swap(b, c);
8434  c = b;
8435  for (;;) {
8436  do {
8437  b++;
8438  } while (compare_value(ctx, c, b, keys, n_keys));
8439  do {
8440  e--;
8441  } while (compare_value(ctx, e, c, keys, n_keys));
8442  if (b >= e) { break; }
8443  swap(b, e);
8444  }
8445  swap(c, e);
8446  return e;
8447 }
8448 
8449 static void
8450 _sort(grn_ctx *ctx, sort_entry *head, sort_entry *tail, int from, int to,
8451  grn_table_sort_key *keys, int n_keys)
8452 {
8453  sort_entry *c;
8454  if (head < tail && (c = part(ctx, head, tail, keys, n_keys))) {
8455  intptr_t m = c - head + 1;
8456  if (from < m - 1) { _sort(ctx, head, c - 1, from, to, keys, n_keys); }
8457  if (m < to) { _sort(ctx, c + 1, tail, from - m, to - m, keys, n_keys); }
8458  }
8459 }
8460 
8461 static sort_entry *
8462 pack(grn_ctx *ctx, grn_obj *table, sort_entry *head, sort_entry *tail,
8463  grn_table_sort_key *keys, int n_keys)
8464 {
8465  int i = 0;
8466  sort_entry e, c;
8467  grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
8468  if (!tc) { return NULL; }
8469  if ((c.id = grn_table_cursor_next_inline(ctx, tc))) {
8470  c.value = grn_obj_get_value_(ctx, keys->key, c.id, &c.size);
8471  while ((e.id = grn_table_cursor_next_inline(ctx, tc))) {
8472  e.value = grn_obj_get_value_(ctx, keys->key, e.id, &e.size);
8473  if (compare_value(ctx, &c, &e, keys, n_keys)) {
8474  *head++ = e;
8475  } else {
8476  *tail-- = e;
8477  }
8478  i++;
8479  }
8480  *head = c;
8481  i++;
8482  }
8483  grn_table_cursor_close(ctx, tc);
8484  return i > 2 ? head : NULL;
8485 }
8486 
8487 static int
8488 range_is_idp(grn_obj *obj)
8489 {
8490  if (obj && obj->header.type == GRN_ACCESSOR) {
8491  grn_accessor *a;
8492  for (a = (grn_accessor *)obj; a; a = a->next) {
8493  if (a->action == GRN_ACCESSOR_GET_ID) { return 1; }
8494  }
8495  }
8496  return 0;
8497 }
8498 
8499 int
8500 grn_table_sort(grn_ctx *ctx, grn_obj *table, int offset, int limit,
8501  grn_obj *result, grn_table_sort_key *keys, int n_keys)
8502 {
8503  grn_rc rc;
8504  grn_obj *index;
8505  int n, e, i = 0;
8506  sort_entry *array, *ep;
8507  GRN_API_ENTER;
8508  if (!n_keys || !keys) {
8509  WARN(GRN_INVALID_ARGUMENT, "keys is null");
8510  goto exit;
8511  }
8512  if (!table) {
8513  WARN(GRN_INVALID_ARGUMENT, "table is null");
8514  goto exit;
8515  }
8516  if (!(result && result->header.type == GRN_TABLE_NO_KEY)) {
8517  WARN(GRN_INVALID_ARGUMENT, "result is not a array");
8518  goto exit;
8519  }
8520  n = grn_table_size(ctx, table);
8521  if ((rc = grn_normalize_offset_and_limit(ctx, n, &offset, &limit))) {
8522  ERR(rc, "grn_normalize_offset_and_limit failed");
8523  goto exit;
8524  } else {
8525  e = offset + limit;
8526  }
8527  if (keys->flags & GRN_TABLE_SORT_GEO) {
8528  i = grn_geo_table_sort(ctx, table, offset, limit, result, keys, n_keys);
8529  goto exit;
8530  }
8531  if (n_keys == 1 && !GRN_ACCESSORP(keys->key) &&
8532  grn_column_index(ctx, keys->key, GRN_OP_LESS, &index, 1, NULL)) {
8533  grn_id tid;
8534  grn_pat *lexicon = (grn_pat *)grn_ctx_at(ctx, index->header.domain);
8535  grn_pat_cursor *pc = grn_pat_cursor_open(ctx, lexicon, NULL, 0, NULL, 0,
8536  0 /* offset : can be used in unique index */,
8537  -1 /* limit : can be used in unique index */,
8538  (keys->flags & GRN_TABLE_SORT_DESC)
8541  if (pc) {
8542  while (i < e && (tid = grn_pat_cursor_next(ctx, pc))) {
8543  grn_ii_cursor *ic = grn_ii_cursor_open(ctx, (grn_ii *)index, tid, 0, 0, 1, 0);
8544  if (ic) {
8545  grn_ii_posting *posting;
8546  while (i < e && (posting = grn_ii_cursor_next(ctx, ic))) {
8547  if (offset <= i) {
8548  grn_id *v;
8549  if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
8550  *v = posting->rid;
8551  }
8552  i++;
8553  }
8554  grn_ii_cursor_close(ctx, ic);
8555  }
8556  }
8557  grn_pat_cursor_close(ctx, pc);
8558  }
8559  } else {
8560  int j;
8561  grn_table_sort_key *kp;
8562  for (kp = keys, j = n_keys; j; kp++, j--) {
8563  if (range_is_idp(kp->key)) {
8564  kp->offset = KEY_ID;
8565  } else {
8566  grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, kp->key));
8567  if (range->header.type == GRN_TYPE) {
8568  if (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
8569  kp->offset = KEY_BULK;
8570  } else {
8571  uint8_t key_type = range->header.flags & GRN_OBJ_KEY_MASK;
8572  switch (key_type) {
8573  case GRN_OBJ_KEY_UINT :
8574  case GRN_OBJ_KEY_GEO_POINT :
8575  switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
8576  case 1 :
8577  kp->offset = KEY_UINT8;
8578  break;
8579  case 2 :
8580  kp->offset = KEY_UINT16;
8581  break;
8582  case 4 :
8583  kp->offset = KEY_UINT32;
8584  break;
8585  case 8 :
8586  kp->offset = KEY_UINT64;
8587  break;
8588  default :
8589  ERR(GRN_INVALID_ARGUMENT, "unsupported uint value");
8590  goto exit;
8591  }
8592  break;
8593  case GRN_OBJ_KEY_INT :
8594  switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
8595  case 1 :
8596  kp->offset = KEY_INT8;
8597  break;
8598  case 2 :
8599  kp->offset = KEY_INT16;
8600  break;
8601  case 4 :
8602  kp->offset = KEY_INT32;
8603  break;
8604  case 8 :
8605  kp->offset = KEY_INT64;
8606  break;
8607  default :
8608  ERR(GRN_INVALID_ARGUMENT, "unsupported int value");
8609  goto exit;
8610  }
8611  break;
8612  case GRN_OBJ_KEY_FLOAT :
8613  switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
8614  case 4 :
8615  kp->offset = KEY_FLOAT32;
8616  break;
8617  case 8 :
8618  kp->offset = KEY_FLOAT64;
8619  break;
8620  default :
8621  ERR(GRN_INVALID_ARGUMENT, "unsupported float value");
8622  goto exit;
8623  }
8624  break;
8625  }
8626  }
8627  } else {
8628  kp->offset = KEY_UINT32;
8629  }
8630  }
8631  }
8632  if (!(array = GRN_MALLOC(sizeof(sort_entry) * n))) {
8633  goto exit;
8634  }
8635  if ((ep = pack(ctx, table, array, array + n - 1, keys, n_keys))) {
8636  intptr_t m = ep - array + 1;
8637  if (offset < m - 1) { _sort(ctx, array, ep - 1, offset, e, keys, n_keys); }
8638  if (m < e) { _sort(ctx, ep + 1, array + n - 1, offset - m, e - m, keys, n_keys); }
8639  }
8640  {
8641  grn_id *v;
8642  for (i = 0, ep = array + offset; i < limit && ep < array + n; i++, ep++) {
8643  if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
8644  *v = ep->id;
8645  }
8646  GRN_FREE(array);
8647  }
8648  }
8649 exit :
8650  GRN_API_RETURN(i);
8651 }
8652 
8653 static grn_obj *
8654 deftype(grn_ctx *ctx, const char *name,
8655  grn_obj_flags flags, unsigned int size)
8656 {
8657  grn_obj *o = grn_ctx_get(ctx, name, strlen(name));
8658  if (!o) { o = grn_type_create(ctx, name, strlen(name), flags, size); }
8659  return o;
8660 }
8661 
8662 grn_rc
8664 {
8665  grn_id id;
8666  grn_obj *obj, *db = ctx->impl->db;
8667  char buf[] = "Sys00";
8668  grn_obj_register(ctx, db, buf, 5);
8669  obj = deftype(ctx, "Object",
8670  GRN_OBJ_KEY_UINT, sizeof(uint64_t));
8671  if (!obj || DB_OBJ(obj)->id != GRN_DB_OBJECT) { return GRN_FILE_CORRUPT; }
8672  obj = deftype(ctx, "Bool",
8673  GRN_OBJ_KEY_UINT, sizeof(uint8_t));
8674  if (!obj || DB_OBJ(obj)->id != GRN_DB_BOOL) { return GRN_FILE_CORRUPT; }
8675  obj = deftype(ctx, "Int8",
8676  GRN_OBJ_KEY_INT, sizeof(int8_t));
8677  if (!obj || DB_OBJ(obj)->id != GRN_DB_INT8) { return GRN_FILE_CORRUPT; }
8678  obj = deftype(ctx, "UInt8",
8679  GRN_OBJ_KEY_UINT, sizeof(uint8_t));
8680  if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT8) { return GRN_FILE_CORRUPT; }
8681  obj = deftype(ctx, "Int16",
8682  GRN_OBJ_KEY_INT, sizeof(int16_t));
8683  if (!obj || DB_OBJ(obj)->id != GRN_DB_INT16) { return GRN_FILE_CORRUPT; }
8684  obj = deftype(ctx, "UInt16",
8685  GRN_OBJ_KEY_UINT, sizeof(uint16_t));
8686  if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT16) { return GRN_FILE_CORRUPT; }
8687  obj = deftype(ctx, "Int32",
8688  GRN_OBJ_KEY_INT, sizeof(int32_t));
8689  if (!obj || DB_OBJ(obj)->id != GRN_DB_INT32) { return GRN_FILE_CORRUPT; }
8690  obj = deftype(ctx, "UInt32",
8691  GRN_OBJ_KEY_UINT, sizeof(uint32_t));
8692  if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT32) { return GRN_FILE_CORRUPT; }
8693  obj = deftype(ctx, "Int64",
8694  GRN_OBJ_KEY_INT, sizeof(int64_t));
8695  if (!obj || DB_OBJ(obj)->id != GRN_DB_INT64) { return GRN_FILE_CORRUPT; }
8696  obj = deftype(ctx, "UInt64",
8697  GRN_OBJ_KEY_UINT, sizeof(uint64_t));
8698  if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT64) { return GRN_FILE_CORRUPT; }
8699  obj = deftype(ctx, "Float",
8700  GRN_OBJ_KEY_FLOAT, sizeof(double));
8701  if (!obj || DB_OBJ(obj)->id != GRN_DB_FLOAT) { return GRN_FILE_CORRUPT; }
8702  obj = deftype(ctx, "Time",
8703  GRN_OBJ_KEY_INT, sizeof(int64_t));
8704  if (!obj || DB_OBJ(obj)->id != GRN_DB_TIME) { return GRN_FILE_CORRUPT; }
8705  obj = deftype(ctx, "ShortText",
8707  if (!obj || DB_OBJ(obj)->id != GRN_DB_SHORT_TEXT) { return GRN_FILE_CORRUPT; }
8708  obj = deftype(ctx, "Text",
8709  GRN_OBJ_KEY_VAR_SIZE, 1 << 16);
8710  if (!obj || DB_OBJ(obj)->id != GRN_DB_TEXT) { return GRN_FILE_CORRUPT; }
8711  obj = deftype(ctx, "LongText",
8712  GRN_OBJ_KEY_VAR_SIZE, 1 << 31);
8713  if (!obj || DB_OBJ(obj)->id != GRN_DB_LONG_TEXT) { return GRN_FILE_CORRUPT; }
8714  obj = deftype(ctx, "TokyoGeoPoint",
8716  if (!obj || DB_OBJ(obj)->id != GRN_DB_TOKYO_GEO_POINT) { return GRN_FILE_CORRUPT; }
8717  obj = deftype(ctx, "WGS84GeoPoint",
8719  if (!obj || DB_OBJ(obj)->id != GRN_DB_WGS84_GEO_POINT) { return GRN_FILE_CORRUPT; }
8720  for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_DB_MECAB; id++) {
8721  grn_itoh(id, buf + 3, 2);
8722  grn_obj_register(ctx, db, buf, 5);
8723  }
8724 #ifdef GRN_WITH_MECAB
8725  if (grn_db_init_mecab_tokenizer(ctx)) {
8726  ERRCLR(ctx);
8727 #endif
8728  grn_obj_register(ctx, db, "TokenMecab", 10);
8729 #ifdef GRN_WITH_MECAB
8730  }
8731 #endif
8734  for (id = grn_db_curr_id(ctx, db) + 1; id < 128; id++) {
8735  grn_itoh(id, buf + 3, 2);
8736  grn_obj_register(ctx, db, buf, 5);
8737  }
8739  for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_N_RESERVED_TYPES; id++) {
8740  grn_itoh(id, buf + 3, 2);
8741  grn_obj_register(ctx, db, buf, 5);
8742  }
8743  return ctx->rc;
8744 }
8745 
8746 #define MULTI_COLUMN_INDEXP(i) (DB_OBJ(i)->source_size > sizeof(grn_id))
8747 
8748 static inline int
8749 grn_column_index_column_equal(grn_ctx *ctx, grn_obj *obj, grn_operator op,
8750  grn_obj **indexbuf, int buf_size, int *section)
8751 {
8752  int n = 0;
8753  grn_obj **ip = indexbuf;
8754  grn_hook *hooks;
8755 
8756  for (hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
8757  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
8758  grn_obj *target = grn_ctx_at(ctx, data->target);
8759  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
8760  if (section) { *section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0; }
8761  if (obj->header.type != GRN_COLUMN_FIX_SIZE) {
8762  grn_obj *tokenizer, *lexicon = grn_ctx_at(ctx, target->header.domain);
8763  if (!lexicon) { continue; }
8764  grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL);
8765  if (tokenizer) { continue; }
8766  }
8767  if (n < buf_size) {
8768  *ip++ = target;
8769  }
8770  n++;
8771  }
8772 
8773  return n;
8774 }
8775 
8776 static inline int
8777 grn_column_index_column_match(grn_ctx *ctx, grn_obj *obj, grn_operator op,
8778  grn_obj **indexbuf, int buf_size, int *section)
8779 {
8780  int n = 0;
8781  grn_obj **ip = indexbuf;
8782  grn_hook *hooks;
8783 
8784  for (hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
8785  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
8786  grn_obj *target = grn_ctx_at(ctx, data->target);
8787  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
8788  if (section) { *section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0; }
8789  if (n < buf_size) {
8790  *ip++ = target;
8791  }
8792  n++;
8793  }
8794 
8795  return n;
8796 }
8797 
8798 static inline int
8799 grn_column_index_column_range(grn_ctx *ctx, grn_obj *obj, grn_operator op,
8800  grn_obj **indexbuf, int buf_size, int *section)
8801 {
8802  int n = 0;
8803  grn_obj **ip = indexbuf;
8804  grn_hook_entry hook_entry;
8805  grn_hook *hooks;
8806 
8807  switch (obj->header.type) {
8808  case GRN_TABLE_HASH_KEY :
8809  case GRN_TABLE_PAT_KEY :
8810  case GRN_TABLE_DAT_KEY :
8811  case GRN_TABLE_NO_KEY :
8812  hook_entry = GRN_HOOK_INSERT;
8813  break;
8814  default :
8815  hook_entry = GRN_HOOK_SET;
8816  break;
8817  }
8818 
8819  for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
8820  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
8821  grn_obj *target = grn_ctx_at(ctx, data->target);
8822  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
8823  if (section) { *section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0; }
8824  {
8825  grn_obj *tokenizer, *lexicon = grn_ctx_at(ctx, target->header.domain);
8826  if (!lexicon) { continue; }
8827  if (lexicon->header.type != GRN_TABLE_PAT_KEY) { continue; }
8828  /* FIXME: GRN_TABLE_DAT_KEY should be supported */
8829  grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL);
8830  if (tokenizer) { continue; }
8831  }
8832  if (n < buf_size) {
8833  *ip++ = target;
8834  }
8835  n++;
8836  }
8837 
8838  return n;
8839 }
8840 
8841 static inline grn_bool
8842 is_valid_match_index(grn_ctx *ctx, grn_obj *index_column)
8843 {
8844  return GRN_TRUE;
8845 }
8846 
8847 static inline grn_bool
8848 is_valid_range_index(grn_ctx *ctx, grn_obj *index_column)
8849 {
8850  grn_obj *tokenizer;
8851  grn_obj *lexicon;
8852 
8853  lexicon = grn_ctx_at(ctx, index_column->header.domain);
8854  if (!lexicon) { return GRN_FALSE; }
8855  /* FIXME: GRN_TABLE_DAT_KEY should be supported */
8856  if (lexicon->header.type != GRN_TABLE_PAT_KEY) {
8857  grn_obj_unlink(ctx, lexicon);
8858  return GRN_FALSE;
8859  }
8860 
8861  grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL);
8862  grn_obj_unlink(ctx, lexicon);
8863  if (tokenizer) { return GRN_FALSE; }
8864 
8865  return GRN_TRUE;
8866 }
8867 
8868 static grn_bool
8869 is_valid_index(grn_ctx *ctx, grn_obj *index_column, grn_operator op)
8870 {
8871  switch (op) {
8872  case GRN_OP_MATCH :
8873  case GRN_OP_NEAR :
8874  case GRN_OP_NEAR2 :
8875  case GRN_OP_SIMILAR :
8876  return is_valid_match_index(ctx, index_column);
8877  break;
8878  case GRN_OP_LESS :
8879  case GRN_OP_GREATER :
8880  case GRN_OP_LESS_EQUAL :
8881  case GRN_OP_GREATER_EQUAL :
8882  case GRN_OP_CALL :
8883  return is_valid_range_index(ctx, index_column);
8884  break;
8885  default :
8886  return GRN_FALSE;
8887  break;
8888  }
8889 }
8890 
8891 static int
8892 find_section(grn_ctx *ctx, grn_obj *index_column, grn_obj *indexed_column)
8893 {
8894  int section = 0;
8895  grn_id indexed_column_id;
8896  grn_id *source_ids;
8897  int i, n_source_ids;
8898 
8899  indexed_column_id = DB_OBJ(indexed_column)->id;
8900 
8901  source_ids = DB_OBJ(index_column)->source;
8902  n_source_ids = DB_OBJ(index_column)->source_size / sizeof(grn_id);
8903  for (i = 0; i < n_source_ids; i++) {
8904  grn_id source_id = source_ids[i];
8905  if (source_id == indexed_column_id) {
8906  section = i + 1;
8907  break;
8908  }
8909  }
8910 
8911  return section;
8912 }
8913 
8914 static int
8915 grn_column_index_accessor_index_column(grn_ctx *ctx, grn_accessor *a,
8916  grn_operator op,
8917  grn_obj **indexbuf, int buf_size,
8918  int *section)
8919 {
8920  grn_obj *index_column = a->obj;
8921 
8922  if (!is_valid_index(ctx, index_column, op)) {
8923  return 0;
8924  }
8925 
8926  if (a->next) {
8927  int specified_section;
8928  grn_bool is_invalid_section;
8929  if (a->next->next) {
8930  return 0;
8931  }
8932  specified_section = find_section(ctx, index_column, a->next->obj);
8933  is_invalid_section = (specified_section == 0);
8934  if (is_invalid_section) {
8935  return 0;
8936  }
8937  if (section) {
8938  *section = specified_section;
8939  }
8940  }
8941  if (buf_size > 0) {
8942  *indexbuf = index_column;
8943  }
8944 
8945  return 1;
8946 }
8947 
8948 static inline int
8949 grn_column_index_accessor(grn_ctx *ctx, grn_obj *obj, grn_operator op,
8950  grn_obj **indexbuf, int buf_size, int *section)
8951 {
8952  int n = 0;
8953  grn_obj **ip = indexbuf;
8954  grn_accessor *a = (grn_accessor *)obj;
8955 
8956  while (a) {
8957  grn_hook *hooks;
8958  grn_bool found = GRN_FALSE;
8959  grn_hook_entry entry = -1;
8960 
8962  a->obj->header.type == GRN_COLUMN_INDEX) {
8963  return grn_column_index_accessor_index_column(ctx, a, op, indexbuf,
8964  buf_size, section);
8965  }
8966 
8967  switch (a->action) {
8968  case GRN_ACCESSOR_GET_KEY :
8969  entry = GRN_HOOK_INSERT;
8970  break;
8972  entry = GRN_HOOK_SET;
8973  break;
8974  default :
8975  break;
8976  }
8977 
8978  if (entry == -1) {
8979  break;
8980  }
8981 
8982  for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) {
8983  default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
8984  grn_obj *target = grn_ctx_at(ctx, data->target);
8985 
8986  if (target->header.type != GRN_COLUMN_INDEX) { continue; }
8987 
8988  found = GRN_TRUE;
8989  if (!a->next) {
8990  if (!is_valid_index(ctx, target, op)) {
8991  continue;
8992  }
8993 
8994  if (section) {
8995  *section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
8996  }
8997  if (n < buf_size) {
8998  *ip++ = target;
8999  }
9000  n++;
9001  }
9002  }
9003 
9004  if (!found) {
9005  break;
9006  }
9007  a = a->next;
9008  }
9009 
9010  return n;
9011 }
9012 
9013 int
9015  grn_obj **indexbuf, int buf_size, int *section)
9016 {
9017  int n = 0;
9018  GRN_API_ENTER;
9019  if (GRN_DB_OBJP(obj)) {
9020  switch (op) {
9021  case GRN_OP_EQUAL :
9022  n = grn_column_index_column_equal(ctx, obj, op,
9023  indexbuf, buf_size, section);
9024  break;
9025  case GRN_OP_PREFIX :
9026  case GRN_OP_SUFFIX :
9027  case GRN_OP_MATCH :
9028  case GRN_OP_NEAR :
9029  case GRN_OP_NEAR2 :
9030  case GRN_OP_SIMILAR :
9031  n = grn_column_index_column_match(ctx, obj, op,
9032  indexbuf, buf_size, section);
9033  break;
9034  case GRN_OP_LESS :
9035  case GRN_OP_GREATER :
9036  case GRN_OP_LESS_EQUAL :
9037  case GRN_OP_GREATER_EQUAL :
9038  case GRN_OP_CALL :
9039  n = grn_column_index_column_range(ctx, obj, op,
9040  indexbuf, buf_size, section);
9041  break;
9042  default :
9043  break;
9044  }
9045  } else if (GRN_ACCESSORP(obj)) {
9046  switch (op) {
9047  case GRN_OP_EQUAL :
9048  case GRN_OP_TERM_EXTRACT :
9049  if (buf_size) { indexbuf[n] = obj; }
9050  n++;
9051  break;
9052  case GRN_OP_PREFIX :
9053  {
9054  grn_accessor *a = (grn_accessor *)obj;
9055  if (a->action == GRN_ACCESSOR_GET_KEY) {
9056  if (a->obj->header.type == GRN_TABLE_PAT_KEY) {
9057  if (buf_size) { indexbuf[n] = obj; }
9058  n++;
9059  }
9060  /* FIXME: GRN_TABLE_DAT_KEY should be supported */
9061  }
9062  }
9063  break;
9064  case GRN_OP_SUFFIX :
9065  {
9066  grn_accessor *a = (grn_accessor *)obj;
9067  if (a->action == GRN_ACCESSOR_GET_KEY) {
9068  if (a->obj->header.type == GRN_TABLE_PAT_KEY &&
9069  a->obj->header.flags & GRN_OBJ_KEY_WITH_SIS) {
9070  if (buf_size) { indexbuf[n] = obj; }
9071  n++;
9072  }
9073  }
9074  }
9075  break;
9076  case GRN_OP_MATCH :
9077  case GRN_OP_NEAR :
9078  case GRN_OP_NEAR2 :
9079  case GRN_OP_SIMILAR :
9080  case GRN_OP_LESS :
9081  case GRN_OP_GREATER :
9082  case GRN_OP_LESS_EQUAL :
9083  case GRN_OP_GREATER_EQUAL :
9084  case GRN_OP_CALL :
9085  n = grn_column_index_accessor(ctx, obj, op, indexbuf, buf_size, section);
9086  break;
9087  default :
9088  break;
9089  }
9090  }
9091  GRN_API_RETURN(n);
9092 }
9093 
9094 /* todo : refine */
9095 static int
9096 tokenize(const char *str, size_t str_len, const char **tokbuf, int buf_size, const char **rest)
9097 {
9098  const char **tok = tokbuf, **tok_end = tokbuf + buf_size;
9099  if (buf_size > 0) {
9100  const char *str_end = str + str_len;
9101  while (str < str_end && (' ' == *str || ',' == *str)) { str++; }
9102  for (;;) {
9103  if (str == str_end) {
9104  *tok++ = str;
9105  break;
9106  }
9107  if (' ' == *str || ',' == *str) {
9108  // *str = '\0';
9109  *tok++ = str;
9110  if (tok == tok_end) { break; }
9111  do { str++; } while (str < str_end && (' ' == *str || ',' == *str));
9112  } else {
9113  str++;
9114  }
9115  }
9116  }
9117  if (rest) { *rest = str; }
9118  return tok - tokbuf;
9119 }
9120 
9121 grn_rc
9123  const char *str, unsigned int str_size, grn_obj *res)
9124 {
9125  grn_obj *col;
9126  const char *p = (char *)str, *q, *r, *pe = p + str_size, *tokbuf[256];
9127  while (p < pe) {
9128  int i, n = tokenize(p, pe - p, tokbuf, 256, &q);
9129  for (i = 0; i < n; i++) {
9130  r = tokbuf[i];
9131  while (p < r && (' ' == *p || ',' == *p)) { p++; }
9132  if (p < r) {
9133  if (r[-1] == '*') {
9134  grn_hash *cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
9136  if (cols) {
9137  grn_id *key;
9138  grn_table_columns(ctx, table, p, r - p - 1, (grn_obj *)cols);
9139  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
9140  if ((col = grn_ctx_at(ctx, *key))) { GRN_PTR_PUT(ctx, res, col); }
9141  });
9142  grn_hash_close(ctx, cols);
9143  }
9144  {
9145  grn_obj *type = grn_ctx_at(ctx, table->header.domain);
9146  if (GRN_OBJ_TABLEP(type)) {
9147  grn_obj *ai = grn_obj_column(ctx, table, "_id", 3);
9148  if (ai) {
9149  if (ai->header.type == GRN_ACCESSOR) {
9150  cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
9152  if (cols) {
9153  grn_id *key;
9154  grn_accessor *a, *ac;
9155  grn_obj *target_table = table;
9156  for (a = (grn_accessor *)ai; a; a = a->next) {
9157  target_table = a->obj;
9158  }
9159  grn_table_columns(ctx, target_table,
9160  p, r - p - 1, (grn_obj *)cols);
9161  GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
9162  if ((col = grn_ctx_at(ctx, *key))) {
9163  ac = accessor_new(ctx);
9164  GRN_PTR_PUT(ctx, res, (grn_obj *)ac);
9165  for (a = (grn_accessor *)ai; a; a = a->next) {
9166  if (a->action != GRN_ACCESSOR_GET_ID) {
9167  ac->action = a->action;
9168  ac->obj = a->obj;
9169  ac->next = accessor_new(ctx);
9170  if (!(ac = ac->next)) { break; }
9171  } else {
9173  ac->obj = col;
9174  ac->next = NULL;
9175  break;
9176  }
9177  }
9178  }
9179  });
9180  grn_hash_close(ctx, cols);
9181  }
9182  }
9183  grn_obj_unlink(ctx, ai);
9184  }
9185  }
9186  }
9187  } else if ((col = grn_obj_column(ctx, table, p, r - p))) {
9188  GRN_PTR_PUT(ctx, res, col);
9189  }
9190  }
9191  p = r;
9192  }
9193  p = q;
9194  }
9195  return ctx->rc;
9196 }
9197 
9198 static grn_table_sort_key *
9199 grn_table_sort_key_from_str_geo(grn_ctx *ctx, const char *str, unsigned int str_size,
9200  grn_obj *table, unsigned int *nkeys)
9201 {
9202  const char **tokbuf;
9203  const char *p = str, *pe = str + str_size;
9204  grn_table_sort_key *keys = NULL, *k = NULL;
9205  while ((*p++ != '(')) { if (p == pe) { return NULL; } }
9206  str = p;
9207  while ((*p != ')')) { if (++p == pe) { return NULL; } }
9208  str_size = p - str;
9209  p = str;
9210  if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
9211  grn_id domain = GRN_ID_NIL;
9212  int i, n = tokenize(str, str_size, tokbuf, str_size, NULL);
9213  if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
9214  k = keys;
9215  for (i = 0; i < n; i++) {
9216  const char *r = tokbuf[i];
9217  while (p < r && (' ' == *p || ',' == *p)) { p++; }
9218  if (p < r) {
9220  k->offset = 0;
9221  if (*p == '+') {
9222  p++;
9223  } else if (*p == '-') {
9224  k->flags = GRN_TABLE_SORT_DESC;
9225  p++;
9226  }
9227  if (k == keys) {
9228  if (!(k->key = grn_obj_column(ctx, table, p, r - p))) {
9229  WARN(GRN_INVALID_ARGUMENT, "invalid sort key: <%.*s>(<%.*s>)",
9230  (int)(tokbuf[i] - p), p, str_size, str);
9231  break;
9232  }
9233  domain = grn_obj_get_range(ctx, k->key);
9234  } else {
9235  grn_obj buf;
9237  GRN_TEXT_SET(ctx, &buf, p + 1, r - p - 2); /* should be quoted */
9238  k->key = grn_obj_open(ctx, GRN_BULK, 0, domain);
9239  grn_obj_cast(ctx, &buf, k->key, GRN_FALSE);
9240  GRN_OBJ_FIN(ctx, &buf);
9241  }
9242  k->flags |= GRN_TABLE_SORT_GEO;
9243  k++;
9244  }
9245  p = r;
9246  }
9247  }
9248  GRN_FREE(tokbuf);
9249  }
9250  if (!ctx->rc && k - keys > 0) {
9251  *nkeys = k - keys;
9252  } else {
9253  grn_table_sort_key_close(ctx, keys, k - keys);
9254  *nkeys = 0;
9255  keys = NULL;
9256  }
9257  return keys;
9258 }
9259 
9261 grn_table_sort_key_from_str(grn_ctx *ctx, const char *str, unsigned int str_size,
9262  grn_obj *table, unsigned int *nkeys)
9263 {
9264  const char *p = str;
9265  const char **tokbuf;
9266  grn_table_sort_key *keys = NULL, *k = NULL;
9267  if ((keys = grn_table_sort_key_from_str_geo(ctx, str, str_size, table, nkeys))) {
9268  return keys;
9269  }
9270  if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
9271  int i, n = tokenize(str, str_size, tokbuf, str_size, NULL);
9272  if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
9273  k = keys;
9274  for (i = 0; i < n; i++) {
9275  const char *r = tokbuf[i];
9276  while (p < r && (' ' == *p || ',' == *p)) { p++; }
9277  if (p < r) {
9279  k->offset = 0;
9280  if (*p == '+') {
9281  p++;
9282  } else if (*p == '-') {
9283  k->flags = GRN_TABLE_SORT_DESC;
9284  p++;
9285  }
9286  if ((k->key = grn_obj_column(ctx, table, p, r - p))) {
9287  k++;
9288  } else {
9289  if (r - p == 6 && memcmp(p, "_score", 6) == 0) {
9290  GRN_LOG(ctx, GRN_WARN,
9291  "ignore invalid sort key: <%.*s>(<%.*s>)",
9292  (int)(r - p), p, str_size, str);
9293  } else {
9295  "invalid sort key: <%.*s>(<%.*s>)",
9296  (int)(r - p), p, str_size, str);
9297  break;
9298  }
9299  }
9300  }
9301  p = r;
9302  }
9303  }
9304  GRN_FREE(tokbuf);
9305  }
9306  if (!ctx->rc && k - keys > 0) {
9307  *nkeys = k - keys;
9308  } else {
9309  grn_table_sort_key_close(ctx, keys, k - keys);
9310  *nkeys = 0;
9311  keys = NULL;
9312  }
9313  return keys;
9314 }
9315 
9316 grn_rc
9317 grn_table_sort_key_close(grn_ctx *ctx, grn_table_sort_key *keys, unsigned int nkeys)
9318 {
9319  int i;
9320  if (keys) {
9321  for (i = 0; i < nkeys; i++) {
9322  grn_obj_unlink(ctx, keys[i].key);
9323  }
9324  GRN_FREE(keys);
9325  }
9326  return ctx->rc;
9327 }
9328 
9329 grn_bool
9331 {
9332  if (GRN_OBJ_TABLEP(table) && GRN_TABLE_IS_GROUPED(table)) {
9333  return GRN_TRUE;
9334  }
9335  return GRN_FALSE;
9336 }
9337 
9338 unsigned int
9340 {
9341  if (GRN_OBJ_TABLEP(table)) {
9342  return DB_OBJ(table)->max_n_subrecs;
9343  }
9344  return 0;
9345 }
9346 
9347 grn_obj *
9349  const char *str, unsigned int str_len,
9350  grn_obj *buf, grn_bool addp)
9351 {
9352  grn_token *token = NULL;
9353  grn_token_mode mode = addp ? GRN_TOKEN_ADD : GRN_TOKEN_GET;
9354  GRN_API_ENTER;
9355  if (!(token = grn_token_open(ctx, table, str, str_len, mode, 0))) {
9356  goto exit;
9357  }
9358  if (buf) {
9359  GRN_BULK_REWIND(buf);
9360  } else {
9361  if (!(buf = grn_obj_open(ctx, GRN_UVECTOR, 0, DB_OBJ(table)->id))) {
9362  goto exit;
9363  }
9364  }
9365  while (token->status != GRN_TOKEN_DONE) {
9366  grn_id tid;
9367  if ((tid = grn_token_next(ctx, token))) {
9368  GRN_RECORD_PUT(ctx, buf, tid);
9369  }
9370  }
9371 exit :
9372  if (token) {
9373  grn_token_close(ctx, token);
9374  }
9375  GRN_API_RETURN(buf);
9376 }
9377 
9378 /* grn_load */
9379 
9380 static grn_obj *
9381 values_add(grn_ctx *ctx, grn_loader *loader)
9382 {
9383  grn_obj *res;
9384  uint32_t curr_size = loader->values_size * sizeof(grn_obj);
9385  if (curr_size < GRN_TEXT_LEN(&loader->values)) {
9386  res = (grn_obj *)(GRN_TEXT_VALUE(&loader->values) + curr_size);
9387  res->header.domain = GRN_DB_TEXT;
9388  GRN_BULK_REWIND(res);
9389  } else {
9390  if (grn_bulk_space(ctx, &loader->values, sizeof(grn_obj))) { return NULL; }
9391  res = (grn_obj *)(GRN_TEXT_VALUE(&loader->values) + curr_size);
9392  GRN_TEXT_INIT(res, 0);
9393  }
9394  loader->values_size++;
9395  loader->last = res;
9396  return res;
9397 }
9398 
9399 #define OPEN_BRACKET 0x40000000
9400 #define OPEN_BRACE 0x40000001
9401 
9402 static grn_obj *
9403 values_next(grn_ctx *ctx, grn_obj *value)
9404 {
9405  if (value->header.domain & OPEN_BRACKET) {
9406  value += GRN_UINT32_VALUE(value);
9407  }
9408  return value + 1;
9409 }
9410 
9411 static int
9412 values_len(grn_ctx *ctx, grn_obj *head, grn_obj *tail)
9413 {
9414  int len;
9415  for (len = 0; head < tail; head = values_next(ctx, head), len++) ;
9416  return len;
9417 }
9418 
9419 static grn_id
9420 loader_add(grn_ctx *ctx, grn_obj *key)
9421 {
9422  int added = 0;
9423  grn_loader *loader = &ctx->impl->loader;
9424  grn_id id = grn_table_add_by_key(ctx, loader->table, key, &added);
9425  if (!added && loader->ifexists) {
9426  grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->ifexists, 0);
9427  grn_obj *result;
9428  unsigned int result_boolean;
9429  GRN_RECORD_SET(ctx, v, id);
9430  result = grn_expr_exec(ctx, loader->ifexists, 0);
9431  GRN_TRUEP(ctx, result, result_boolean);
9432  if (!result_boolean) { id = 0; }
9433  }
9434  return id;
9435 }
9436 
9437 static void
9438 set_vector(grn_ctx *ctx, grn_obj *column, grn_id id, grn_obj *vector)
9439 {
9440  int n = GRN_UINT32_VALUE(vector);
9441  grn_obj buf, *v = vector + 1;
9442  grn_id range_id;
9443  grn_obj *range;
9444 
9445  range_id = DB_OBJ(column)->range;
9446  range = grn_ctx_at(ctx, range_id);
9447  if (GRN_OBJ_TABLEP(range)) {
9448  GRN_RECORD_INIT(&buf, GRN_OBJ_VECTOR, range_id);
9449  while (n--) {
9450  grn_bool cast_failed = GRN_FALSE;
9451  grn_obj record, *element = v;
9452  if (range_id != element->header.domain) {
9453  GRN_RECORD_INIT(&record, 0, range_id);
9454  if (grn_obj_cast(ctx, element, &record, GRN_TRUE)) {
9455  cast_failed = GRN_TRUE;
9456  REPORT_CAST_ERROR(column, range, element);
9457  }
9458  element = &record;
9459  }
9460  if (!cast_failed) {
9461  GRN_UINT32_PUT(ctx, &buf, GRN_RECORD_VALUE(element));
9462  }
9463  if (element == &record) { GRN_OBJ_FIN(ctx, element); }
9464  v = values_next(ctx, v);
9465  }
9466  } else {
9467  if (((struct _grn_type *)range)->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
9469  while (n--) {
9470  if (v->header.domain == GRN_DB_TEXT) {
9471  grn_bool cast_failed = GRN_FALSE;
9472  grn_obj casted_element, *element = v;
9473  if (range_id != element->header.domain) {
9474  GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
9475  if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
9476  cast_failed = GRN_TRUE;
9477  REPORT_CAST_ERROR(column, range, element);
9478  }
9479  element = &casted_element;
9480  }
9481  if (!cast_failed) {
9482  grn_vector_add_element(ctx, &buf,
9483  GRN_TEXT_VALUE(element),
9484  GRN_TEXT_LEN(element), 0,
9485  element->header.domain);
9486  }
9487  if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
9488  } else {
9489  ERR(GRN_INVALID_ARGUMENT, "bad syntax.");
9490  }
9491  v = values_next(ctx, v);
9492  }
9493  } else {
9494  grn_id value_size = ((grn_db_obj *)range)->range;
9495  GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, range_id);
9496  while (n--) {
9497  grn_bool cast_failed = GRN_FALSE;
9498  grn_obj casted_element, *element = v;
9499  if (range_id != element->header.domain) {
9500  GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
9501  if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
9502  cast_failed = GRN_TRUE;
9503  REPORT_CAST_ERROR(column, range, element);
9504  }
9505  element = &casted_element;
9506  }
9507  if (!cast_failed) {
9508  grn_bulk_write(ctx, &buf, GRN_TEXT_VALUE(element), value_size);
9509  }
9510  if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
9511  v = values_next(ctx, v);
9512  }
9513  }
9514  }
9515  grn_obj_set_value(ctx, column, id, &buf, GRN_OBJ_SET);
9516  GRN_OBJ_FIN(ctx, &buf);
9517 }
9518 
9519 static inline int
9520 name_equal(const char *p, unsigned int size, const char *name)
9521 {
9522  if (strlen(name) != size) { return 0; }
9523  if (*p != GRN_DB_PSEUDO_COLUMN_PREFIX) { return 0; }
9524  return !memcmp(p + 1, name + 1, size - 1);
9525 }
9526 
9527 static void
9528 report_set_column_value_failure(grn_ctx *ctx,
9529  grn_obj *key,
9530  const char *column_name,
9531  unsigned int column_name_size,
9532  grn_obj *column_value)
9533 {
9534  grn_obj key_inspected, column_value_inspected;
9535 
9536  GRN_TEXT_INIT(&key_inspected, 0);
9537  GRN_TEXT_INIT(&column_value_inspected, 0);
9538  limited_size_inspect(ctx, &key_inspected, key);
9539  limited_size_inspect(ctx, &column_value_inspected, column_value);
9540  GRN_LOG(ctx, GRN_LOG_ERROR,
9541  "[table][load] failed to set column value: %s: "
9542  "key: <%.*s>, column: <%.*s>, value: <%.*s>",
9543  ctx->errbuf,
9544  (int)GRN_TEXT_LEN(&key_inspected),
9545  GRN_TEXT_VALUE(&key_inspected),
9546  column_name_size,
9547  column_name,
9548  (int)GRN_TEXT_LEN(&column_value_inspected),
9549  GRN_TEXT_VALUE(&column_value_inspected));
9550  GRN_OBJ_FIN(ctx, &key_inspected);
9551  GRN_OBJ_FIN(ctx, &column_value_inspected);
9552 }
9553 
9554 static void
9555 bracket_close(grn_ctx *ctx, grn_loader *loader)
9556 {
9557  grn_obj *value, *col, *ve;
9558  grn_id id = GRN_ID_NIL;
9559  grn_obj *key_value = NULL;
9560  grn_obj **cols = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
9561  uint32_t begin, ndata, ncols = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
9562  GRN_UINT32_POP(&loader->level, begin);
9563  value = ((grn_obj *)(GRN_TEXT_VALUE(&loader->values))) + begin;
9564  ve = ((grn_obj *)(GRN_TEXT_VALUE(&loader->values))) + loader->values_size;
9566  GRN_UINT32_SET(ctx, value, loader->values_size - begin - 1);
9567  value++;
9568  if (GRN_BULK_VSIZE(&loader->level) <= sizeof(uint32_t) * loader->emit_level) {
9569  ndata = values_len(ctx, value, ve);
9570  if (loader->table) {
9571  switch (loader->table->header.type) {
9572  case GRN_TABLE_HASH_KEY :
9573  case GRN_TABLE_PAT_KEY :
9574  case GRN_TABLE_DAT_KEY :
9575  if (loader->key_offset != -1 && ndata == ncols + 1) {
9576  key_value = value + loader->key_offset;
9577  id = loader_add(ctx, key_value);
9578  } else if (loader->key_offset == -1) {
9579  int i = 0;
9580  grn_obj *key_column_name = NULL;
9581  while (ndata--) {
9582  char *column_name = GRN_TEXT_VALUE(value);
9583  unsigned int column_name_size = GRN_TEXT_LEN(value);
9584  if (value->header.domain == GRN_DB_TEXT &&
9585  (name_equal(column_name, column_name_size, KEY_NAME) ||
9586  name_equal(column_name, column_name_size, ID_NAME))) {
9587  if (loader->key_offset != -1) {
9588  GRN_LOG(ctx, GRN_LOG_ERROR,
9589  "duplicated key columns: <%.*s> at %d and <%.*s> at %i",
9590  (int)GRN_TEXT_LEN(key_column_name),
9591  GRN_TEXT_VALUE(key_column_name),
9592  loader->key_offset,
9593  column_name_size, column_name, i);
9594  return;
9595  }
9596  key_column_name = value;
9597  loader->key_offset = i;
9598  } else {
9599  col = grn_obj_column(ctx, loader->table,
9600  column_name, column_name_size);
9601  if (!col) {
9603  "nonexistent column: <%.*s>",
9604  column_name_size, column_name);
9605  return;
9606  }
9607  GRN_PTR_PUT(ctx, &loader->columns, col);
9608  }
9609  value++;
9610  i++;
9611  }
9612  }
9613  break;
9614  case GRN_TABLE_NO_KEY :
9615  if ((GRN_BULK_VSIZE(&loader->level)) > 0 &&
9616  (ndata == 0 || ndata == ncols)) {
9617  id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
9618  } else if (!ncols) {
9619  while (ndata--) {
9620  if (value->header.domain == GRN_DB_TEXT) {
9621  char *column_name = GRN_TEXT_VALUE(value);
9622  unsigned int column_name_size = GRN_TEXT_LEN(value);
9623  col = grn_obj_column(ctx, loader->table,
9624  column_name, column_name_size);
9625  if (!col) {
9627  "nonexistent column: <%.*s>",
9628  column_name_size, column_name);
9629  return;
9630  }
9631  GRN_PTR_PUT(ctx, &loader->columns, col);
9632  value++;
9633  } else {
9634  grn_obj buffer;
9635  GRN_TEXT_INIT(&buffer, 0);
9636  grn_inspect(ctx, &buffer, value);
9638  "column name must be string: <%.*s>",
9639  (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
9640  GRN_OBJ_FIN(ctx, &buffer);
9641  return;
9642  }
9643  }
9644  }
9645  break;
9646  default :
9647  break;
9648  }
9649  if (id) {
9650  int i = 0;
9651  while (ndata--) {
9652  grn_obj *column;
9653  if ((loader->table->header.type == GRN_TABLE_HASH_KEY ||
9654  loader->table->header.type == GRN_TABLE_PAT_KEY ||
9655  loader->table->header.type == GRN_TABLE_DAT_KEY) &&
9656  i == loader->key_offset) {
9657  /* skip this value, because it's already used as key value */
9658  value = values_next(ctx, value);
9659  i++;
9660  continue;
9661  }
9662 
9663  column = *cols;
9664  if (value->header.domain == OPEN_BRACKET) {
9665  set_vector(ctx, column, id, value);
9666  } else if (value->header.domain == OPEN_BRACE) {
9667  /* todo */
9668  } else {
9669  grn_obj_set_value(ctx, column, id, value, GRN_OBJ_SET);
9670  }
9671  if (ctx->rc != GRN_SUCCESS) {
9672  char column_name[GRN_TABLE_MAX_KEY_SIZE];
9673  unsigned int column_name_size;
9674  column_name_size = grn_obj_name(ctx, column, column_name,
9676  report_set_column_value_failure(ctx, key_value,
9677  column_name, column_name_size,
9678  value);
9679  ERRCLR(ctx);
9680  }
9681  value = values_next(ctx, value);
9682  cols++;
9683  i++;
9684  }
9685  if (loader->each) {
9686  grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->each, 0);
9687  GRN_RECORD_SET(ctx, v, id);
9688  grn_expr_exec(ctx, loader->each, 0);
9689  }
9690  loader->nrecords++;
9691  }
9692  }
9693  loader->values_size = begin;
9694  }
9695 }
9696 
9697 static void
9698 brace_close(grn_ctx *ctx, grn_loader *loader)
9699 {
9700  uint32_t begin;
9701  grn_obj *key_value = NULL;
9702  grn_obj *value, *ve;
9703  grn_id id = GRN_ID_NIL;
9704  GRN_UINT32_POP(&loader->level, begin);
9705  value = ((grn_obj *)(GRN_TEXT_VALUE(&loader->values))) + begin;
9706  ve = ((grn_obj *)(GRN_TEXT_VALUE(&loader->values))) + loader->values_size;
9708  GRN_UINT32_SET(ctx, value, loader->values_size - begin - 1);
9709  value++;
9710  if (GRN_BULK_VSIZE(&loader->level) <= sizeof(uint32_t) * loader->emit_level) {
9711  if (loader->table) {
9712  switch (loader->table->header.type) {
9713  case GRN_TABLE_HASH_KEY :
9714  case GRN_TABLE_PAT_KEY :
9715  case GRN_TABLE_DAT_KEY :
9716  {
9717  grn_obj *v, *key_column_name = NULL;
9718  for (v = value; v + 1 < ve; v = values_next(ctx, v)) {
9719  char *column_name = GRN_TEXT_VALUE(v);
9720  unsigned int column_name_size = GRN_TEXT_LEN(v);
9721  if (v->header.domain == GRN_DB_TEXT &&
9722  (name_equal(column_name, column_name_size, KEY_NAME) ||
9723  name_equal(column_name, column_name_size, ID_NAME))) {
9724  if (key_column_name) {
9725  GRN_LOG(ctx, GRN_LOG_ERROR, "duplicated key columns: %.*s and %.*s",
9726  (int)GRN_TEXT_LEN(key_column_name),
9727  GRN_TEXT_VALUE(key_column_name),
9728  column_name_size, column_name);
9729  return;
9730  }
9731  key_column_name = value;
9732  v++;
9733  key_value = v;
9734  id = loader_add(ctx, key_value);
9735  } else {
9736  v = values_next(ctx, v);
9737  }
9738  }
9739  }
9740  break;
9741  case GRN_TABLE_NO_KEY :
9742  id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
9743  break;
9744  default :
9745  break;
9746  }
9747  if (id) {
9748  grn_obj *col;
9749  const char *name;
9750  unsigned int name_size;
9751  while (value + 1 < ve) {
9752  if (value->header.domain != GRN_DB_TEXT) { break; /* error */ }
9753  name = GRN_TEXT_VALUE(value);
9754  name_size = GRN_TEXT_LEN(value);
9755  col = grn_obj_column(ctx, loader->table, name, name_size);
9756  value++;
9757  /* auto column create
9758  if (!col) {
9759  if (value->header.domain == OPEN_BRACKET) {
9760  grn_obj *v = value + 1;
9761  col = grn_column_create(ctx, loader->table, name, name_size,
9762  NULL, GRN_OBJ_PERSISTENT|GRN_OBJ_COLUMN_VECTOR,
9763  grn_ctx_at(ctx, v->header.domain));
9764  } else {
9765  col = grn_column_create(ctx, loader->table, name, name_size,
9766  NULL, GRN_OBJ_PERSISTENT,
9767  grn_ctx_at(ctx, value->header.domain));
9768  }
9769  }
9770  */
9771  if (col) {
9772  if (value->header.domain == OPEN_BRACKET) {
9773  set_vector(ctx, col, id, value);
9774  } else if (value->header.domain == OPEN_BRACE) {
9775  /* todo */
9776  } else {
9777  grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
9778  }
9779  if (ctx->rc != GRN_SUCCESS) {
9780  report_set_column_value_failure(ctx, key_value,
9781  name, name_size, value);
9782  ERRCLR(ctx);
9783  }
9784  grn_obj_unlink(ctx, col);
9785  } else {
9786  GRN_LOG(ctx, GRN_LOG_ERROR, "invalid column('%.*s')", (int)name_size, name);
9787  }
9788  value = values_next(ctx, value);
9789  }
9790  if (loader->each) {
9791  grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->each, 0);
9792  GRN_RECORD_SET(ctx, v, id);
9793  grn_expr_exec(ctx, loader->each, 0);
9794  }
9795  loader->nrecords++;
9796  } else {
9797  GRN_LOG(ctx, GRN_LOG_ERROR, "neither _key nor _id is assigned");
9798  }
9799  }
9800  loader->values_size = begin;
9801  }
9802 }
9803 
9804 #define JSON_READ_OPEN_BRACKET() do {\
9805  GRN_UINT32_PUT(ctx, &loader->level, loader->values_size);\
9806  values_add(ctx, loader);\
9807  loader->last->header.domain = OPEN_BRACKET;\
9808  loader->stat = GRN_LOADER_TOKEN;\
9809  str++;\
9810 } while (0)
9811 
9812 #define JSON_READ_OPEN_BRACE() do {\
9813  GRN_UINT32_PUT(ctx, &loader->level, loader->values_size);\
9814  values_add(ctx, loader);\
9815  loader->last->header.domain = OPEN_BRACE;\
9816  loader->stat = GRN_LOADER_TOKEN;\
9817  str++;\
9818 } while (0)
9819 
9820 static void
9821 json_read(grn_ctx *ctx, grn_loader *loader, const char *str, unsigned int str_len)
9822 {
9823  const char *const beg = str;
9824  char c;
9825  int len;
9826  const char *se = str + str_len;
9827  while (str < se) {
9828  c = *str;
9829  switch (loader->stat) {
9830  case GRN_LOADER_BEGIN :
9831  if ((len = grn_isspace(str, ctx->encoding))) {
9832  str += len;
9833  c = *str;
9834  continue;
9835  }
9836  switch (c) {
9837  case '[' :
9839  break;
9840  case '{' :
9842  break;
9843  default :
9845  "JSON must start with '[' or '{': <%.*s>", str_len, beg);
9846  loader->stat = GRN_LOADER_END;
9847  break;
9848  }
9849  break;
9850  case GRN_LOADER_TOKEN :
9851  if ((len = grn_isspace(str, ctx->encoding))) {
9852  str += len;
9853  c = *str;
9854  continue;
9855  }
9856  switch (c) {
9857  case '"' :
9858  loader->stat = GRN_LOADER_STRING;
9859  values_add(ctx, loader);
9860  str++;
9861  break;
9862  case '[' :
9864  break;
9865  case '{' :
9867  break;
9868  case ':' :
9869  str++;
9870  break;
9871  case ',' :
9872  str++;
9873  break;
9874  case ']' :
9875  bracket_close(ctx, loader);
9876  loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
9877  str++;
9878  break;
9879  case '}' :
9880  brace_close(ctx, loader);
9881  loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
9882  str++;
9883  break;
9884  case '+' : case '-' : case '0' : case '1' : case '2' : case '3' :
9885  case '4' : case '5' : case '6' : case '7' : case '8' : case '9' :
9886  loader->stat = GRN_LOADER_NUMBER;
9887  values_add(ctx, loader);
9888  break;
9889  default :
9890  if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('_' == c)) {
9891  loader->stat = GRN_LOADER_SYMBOL;
9892  values_add(ctx, loader);
9893  } else {
9894  if ((len = grn_charlen(ctx, str, se))) {
9895  GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char('%c') at", c);
9896  GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg) + len, beg);
9897  GRN_LOG(ctx, GRN_LOG_ERROR, "%*s", (int)(str - beg) + 1, "^");
9898  str += len;
9899  } else {
9900  GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char(\\x%.2x) after", c);
9901  GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg), beg);
9902  str = se;
9903  }
9904  }
9905  break;
9906  }
9907  break;
9908  case GRN_LOADER_SYMBOL :
9909  if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') ||
9910  ('0' <= c && c <= '9') || ('_' == c)) {
9911  GRN_TEXT_PUTC(ctx, loader->last, c);
9912  str++;
9913  } else {
9914  char *v = GRN_TEXT_VALUE(loader->last);
9915  switch (*v) {
9916  case 'n' :
9917  if (GRN_TEXT_LEN(loader->last) == 4 && !memcmp(v, "null", 4)) {
9918  loader->last->header.domain = GRN_DB_VOID;
9919  GRN_BULK_REWIND(loader->last);
9920  }
9921  break;
9922  case 't' :
9923  if (GRN_TEXT_LEN(loader->last) == 4 && !memcmp(v, "true", 4)) {
9924  loader->last->header.domain = GRN_DB_BOOL;
9925  GRN_BOOL_SET(ctx, loader->last, GRN_TRUE);
9926  }
9927  break;
9928  case 'f' :
9929  if (GRN_TEXT_LEN(loader->last) == 5 && !memcmp(v, "false", 5)) {
9930  loader->last->header.domain = GRN_DB_BOOL;
9931  GRN_BOOL_SET(ctx, loader->last, GRN_FALSE);
9932  }
9933  break;
9934  default :
9935  break;
9936  }
9937  loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
9938  }
9939  break;
9940  case GRN_LOADER_NUMBER :
9941  switch (c) {
9942  case '+' : case '-' : case '.' : case 'e' : case 'E' :
9943  case '0' : case '1' : case '2' : case '3' : case '4' :
9944  case '5' : case '6' : case '7' : case '8' : case '9' :
9945  GRN_TEXT_PUTC(ctx, loader->last, c);
9946  str++;
9947  break;
9948  default :
9949  {
9950  const char *cur, *str = GRN_BULK_HEAD(loader->last);
9951  const char *str_end = GRN_BULK_CURR(loader->last);
9952  int64_t i = grn_atoll(str, str_end, &cur);
9953  if (cur == str_end) {
9954  loader->last->header.domain = GRN_DB_INT64;
9955  GRN_INT64_SET(ctx, loader->last, i);
9956  } else if (cur != str) {
9957  double d;
9958  char *end;
9959  grn_obj buf;
9960  GRN_TEXT_INIT(&buf, 0);
9961  GRN_TEXT_PUT(ctx, &buf, str, GRN_BULK_VSIZE(loader->last));
9962  GRN_TEXT_PUTC(ctx, &buf, '\0');
9963  errno = 0;
9964  d = strtod(GRN_TEXT_VALUE(&buf), &end);
9965  if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
9966  loader->last->header.domain = GRN_DB_FLOAT;
9967  GRN_FLOAT_SET(ctx, loader->last, d);
9968  }
9969  GRN_OBJ_FIN(ctx, &buf);
9970  }
9971  }
9972  loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
9973  break;
9974  }
9975  break;
9976  case GRN_LOADER_STRING :
9977  switch (c) {
9978  case '\\' :
9979  loader->stat = GRN_LOADER_STRING_ESC;
9980  str++;
9981  break;
9982  case '"' :
9983  str++;
9984  loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
9985  /*
9986  *(GRN_BULK_CURR(loader->last)) = '\0';
9987  GRN_LOG(ctx, GRN_LOG_ALERT, "read str(%s)", GRN_TEXT_VALUE(loader->last));
9988  */
9989  break;
9990  default :
9991  if ((len = grn_charlen(ctx, str, se))) {
9992  GRN_TEXT_PUT(ctx, loader->last, str, len);
9993  str += len;
9994  } else {
9995  GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char(\\x%.2x) after", c);
9996  GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg), beg);
9997  str = se;
9998  }
9999  break;
10000  }
10001  break;
10002  case GRN_LOADER_STRING_ESC :
10003  switch (c) {
10004  case 'b' :
10005  GRN_TEXT_PUTC(ctx, loader->last, '\b');
10006  loader->stat = GRN_LOADER_STRING;
10007  break;
10008  case 'f' :
10009  GRN_TEXT_PUTC(ctx, loader->last, '\f');
10010  loader->stat = GRN_LOADER_STRING;
10011  break;
10012  case 'n' :
10013  GRN_TEXT_PUTC(ctx, loader->last, '\n');
10014  loader->stat = GRN_LOADER_STRING;
10015  break;
10016  case 'r' :
10017  GRN_TEXT_PUTC(ctx, loader->last, '\r');
10018  loader->stat = GRN_LOADER_STRING;
10019  break;
10020  case 't' :
10021  GRN_TEXT_PUTC(ctx, loader->last, '\t');
10022  loader->stat = GRN_LOADER_STRING;
10023  break;
10024  case 'u' :
10025  loader->stat = GRN_LOADER_UNICODE0;
10026  break;
10027  default :
10028  GRN_TEXT_PUTC(ctx, loader->last, c);
10029  loader->stat = GRN_LOADER_STRING;
10030  break;
10031  }
10032  str++;
10033  break;
10034  case GRN_LOADER_UNICODE0 :
10035  switch (c) {
10036  case '0' : case '1' : case '2' : case '3' : case '4' :
10037  case '5' : case '6' : case '7' : case '8' : case '9' :
10038  loader->unichar = (c - '0') * 0x1000;
10039  break;
10040  case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
10041  loader->unichar = (c - 'a' + 10) * 0x1000;
10042  break;
10043  case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
10044  loader->unichar = (c - 'A' + 10) * 0x1000;
10045  break;
10046  default :
10047  ;// todo : error
10048  }
10049  loader->stat = GRN_LOADER_UNICODE1;
10050  str++;
10051  break;
10052  case GRN_LOADER_UNICODE1 :
10053  switch (c) {
10054  case '0' : case '1' : case '2' : case '3' : case '4' :
10055  case '5' : case '6' : case '7' : case '8' : case '9' :
10056  loader->unichar += (c - '0') * 0x100;
10057  break;
10058  case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
10059  loader->unichar += (c - 'a' + 10) * 0x100;
10060  break;
10061  case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
10062  loader->unichar += (c - 'A' + 10) * 0x100;
10063  break;
10064  default :
10065  ;// todo : error
10066  }
10067  loader->stat = GRN_LOADER_UNICODE2;
10068  str++;
10069  break;
10070  case GRN_LOADER_UNICODE2 :
10071  switch (c) {
10072  case '0' : case '1' : case '2' : case '3' : case '4' :
10073  case '5' : case '6' : case '7' : case '8' : case '9' :
10074  loader->unichar += (c - '0') * 0x10;
10075  break;
10076  case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
10077  loader->unichar += (c - 'a' + 10) * 0x10;
10078  break;
10079  case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
10080  loader->unichar += (c - 'A' + 10) * 0x10;
10081  break;
10082  default :
10083  ;// todo : error
10084  }
10085  loader->stat = GRN_LOADER_UNICODE3;
10086  str++;
10087  break;
10088  case GRN_LOADER_UNICODE3 :
10089  switch (c) {
10090  case '0' : case '1' : case '2' : case '3' : case '4' :
10091  case '5' : case '6' : case '7' : case '8' : case '9' :
10092  loader->unichar += (c - '0');
10093  break;
10094  case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
10095  loader->unichar += (c - 'a' + 10);
10096  break;
10097  case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
10098  loader->unichar += (c - 'A' + 10);
10099  break;
10100  default :
10101  ;// todo : error
10102  }
10103  {
10104  uint32_t u = loader->unichar;
10105  if (u < 0x80) {
10106  GRN_TEXT_PUTC(ctx, loader->last, u);
10107  } else {
10108  if (u < 0x800) {
10109  GRN_TEXT_PUTC(ctx, loader->last, ((u >> 6) & 0x1f) | 0xc0);
10110  } else {
10111  GRN_TEXT_PUTC(ctx, loader->last, (u >> 12) | 0xe0);
10112  GRN_TEXT_PUTC(ctx, loader->last, ((u >> 6) & 0x3f) | 0x80);
10113  }
10114  GRN_TEXT_PUTC(ctx, loader->last, (u & 0x3f) | 0x80);
10115  }
10116  }
10117  loader->stat = GRN_LOADER_STRING;
10118  str++;
10119  break;
10120  case GRN_LOADER_END :
10121  str = se;
10122  break;
10123  }
10124  }
10125 }
10126 
10127 #undef JSON_READ_OPEN_BRACKET
10128 #undef JSON_READ_OPEN_BRACE
10129 
10130 static grn_rc
10131 parse_load_columns(grn_ctx *ctx, grn_obj *table,
10132  const char *str, unsigned int str_size, grn_obj *res)
10133 {
10134  const char *p = (char *)str, *q, *r, *pe = p + str_size, *tokbuf[256];
10135  while (p < pe) {
10136  int i, n = tokenize(p, pe - p, tokbuf, 256, &q);
10137  for (i = 0; i < n; i++) {
10138  grn_obj *col;
10139  r = tokbuf[i];
10140  while (p < r && (' ' == *p || ',' == *p)) { p++; }
10141  col = grn_obj_column(ctx, table, p, r - p);
10142  if (!col) {
10143  ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s>", (int)(r - p), p);
10144  goto exit;
10145  }
10146  GRN_PTR_PUT(ctx, res, col);
10147  p = r;
10148  }
10149  p = q;
10150  }
10151 exit:
10152  return ctx->rc;
10153 }
10154 
10155 static grn_com_addr *addr;
10156 
10157 void
10159  const char *table, unsigned int table_len,
10160  const char *columns, unsigned int columns_len,
10161  const char *values, unsigned int values_len,
10162  const char *ifexists, unsigned int ifexists_len,
10163  const char *each, unsigned int each_len,
10164  uint32_t emit_level)
10165 {
10166  grn_loader *loader;
10167  loader = &ctx->impl->loader;
10168  loader->emit_level = emit_level;
10169  if (ctx->impl->edge) {
10170  grn_edge *edge = grn_edges_add_communicator(ctx, addr);
10171  grn_obj *msg = grn_msg_open(ctx, edge->com, &ctx->impl->edge->send_old);
10172  /* build msg */
10173  grn_edge_dispatch(ctx, edge, msg);
10174  }
10175  if (table && table_len) {
10176  grn_ctx_loader_clear(ctx);
10177  loader->input_type = input_type;
10178  if (grn_db_check_name(ctx, table, table_len)) {
10179  GRN_DB_CHECK_NAME_ERR("[table][load]", table, table_len);
10180  loader->stat = GRN_LOADER_END;
10181  return;
10182  }
10183  loader->table = grn_ctx_get(ctx, table, table_len);
10184  if (!loader->table) {
10185  ERR(GRN_INVALID_ARGUMENT, "nonexistent table: <%.*s>", table_len, table);
10186  loader->stat = GRN_LOADER_END;
10187  return;
10188  }
10189  if (loader->table && columns && columns_len) {
10190  int i, n_columns;
10191  grn_obj parsed_columns;
10192 
10193  GRN_PTR_INIT(&parsed_columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
10194  if (parse_load_columns(ctx, loader->table, columns, columns_len,
10195  &parsed_columns)) {
10196  loader->stat = GRN_LOADER_END;
10197  return;
10198  }
10199  n_columns = GRN_BULK_VSIZE(&parsed_columns) / sizeof(grn_obj *);
10200  for (i = 0; i < n_columns; i++) {
10201  grn_obj *column;
10202  column = GRN_PTR_VALUE_AT(&parsed_columns, i);
10203  if (column->header.type == GRN_ACCESSOR &&
10204  ((grn_accessor *)column)->action == GRN_ACCESSOR_GET_KEY) {
10205  loader->key_offset = i;
10206  grn_obj_unlink(ctx, column);
10207  } else {
10208  GRN_PTR_PUT(ctx, &loader->columns, column);
10209  }
10210  }
10211  GRN_OBJ_FIN(ctx, &parsed_columns);
10212  }
10213  if (ifexists && ifexists_len) {
10214  grn_obj *v;
10215  GRN_EXPR_CREATE_FOR_QUERY(ctx, loader->table, loader->ifexists, v);
10216  if (loader->ifexists && v) {
10217  grn_expr_parse(ctx, loader->ifexists, ifexists, ifexists_len,
10218  NULL, GRN_OP_EQUAL, GRN_OP_AND,
10220  }
10221  }
10222  if (each && each_len) {
10223  grn_obj *v;
10224  GRN_EXPR_CREATE_FOR_QUERY(ctx, loader->table, loader->each, v);
10225  if (loader->each && v) {
10226  grn_expr_parse(ctx, loader->each, each, each_len,
10227  NULL, GRN_OP_EQUAL, GRN_OP_AND,
10229  }
10230  }
10231  } else {
10232  if (!loader->table) {
10233  ERR(GRN_INVALID_ARGUMENT, "mandatory \"table\" parameter is absent");
10234  loader->stat = GRN_LOADER_END;
10235  return;
10236  }
10237  input_type = loader->input_type;
10238  }
10239  switch (input_type) {
10240  case GRN_CONTENT_JSON :
10241  json_read(ctx, loader, values, values_len);
10242  break;
10243  case GRN_CONTENT_NONE :
10244  case GRN_CONTENT_TSV :
10245  case GRN_CONTENT_XML :
10246  case GRN_CONTENT_MSGPACK :
10247  ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "unsupported input_type");
10248  // todo
10249  break;
10250  }
10251 }
10252 
10253 grn_rc
10255  const char *table, unsigned int table_len,
10256  const char *columns, unsigned int columns_len,
10257  const char *values, unsigned int values_len,
10258  const char *ifexists, unsigned int ifexists_len,
10259  const char *each, unsigned int each_len)
10260 {
10261  if (!ctx || !ctx->impl) {
10262  ERR(GRN_INVALID_ARGUMENT, "db not initialized");
10263  return ctx->rc;
10264  }
10265  GRN_API_ENTER;
10266  grn_load_(ctx, input_type, table, table_len,
10267  columns, columns_len, values, values_len,
10268  ifexists, ifexists_len, each, each_len, 1);
10269  GRN_API_RETURN(ctx->rc);
10270 }