1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2009-2017 Brazil
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License version 2.1 as published by the Free Software Foundation.
8 
9   This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
17 */
18 #include "grn.h"
19 #include "grn_config.h"
20 #include "grn_db.h"
21 #include "grn_obj.h"
22 #include "grn_hash.h"
23 #include "grn_pat.h"
24 #include "grn_dat.h"
25 #include "grn_ii.h"
26 #include "grn_index_column.h"
27 #include "grn_ctx_impl.h"
28 #include "grn_token_cursor.h"
29 #include "grn_tokenizers.h"
30 #include "grn_proc.h"
31 #include "grn_plugin.h"
32 #include "grn_geo.h"
33 #include "grn_scorers.h"
34 #include "grn_snip.h"
35 #include "grn_string.h"
36 #include "grn_normalizer.h"
37 #include "grn_report.h"
38 #include "grn_util.h"
39 #include "grn_cache.h"
40 #include "grn_window_functions.h"
41 #include <string.h>
42 #include <math.h>
43 
44 typedef struct {
45   grn_id id;
46   unsigned int weight;
47 } weight_uvector_entry;
48 
49 #define IS_WEIGHT_UVECTOR(obj) ((obj)->header.flags & GRN_OBJ_WITH_WEIGHT)
50 
51 #define GRN_TABLE_GROUPED (0x01<<0)
52 #define GRN_TABLE_IS_GROUPED(table)\
53   ((table)->header.impl_flags & GRN_TABLE_GROUPED)
54 #define GRN_TABLE_GROUPED_ON(table)\
55   ((table)->header.impl_flags |= GRN_TABLE_GROUPED)
56 #define GRN_TABLE_IS_MULTI_KEYS_GROUPED(table)\
57   (GRN_TABLE_IS_GROUPED(table) &&\
58    table->header.domain == GRN_ID_NIL)
59 
60 #define WITH_NORMALIZE(table,key,key_size,block) do {\
61   if ((table)->normalizer && key && key_size > 0) {\
62     grn_obj *nstr;\
63     if ((nstr = grn_string_open(ctx, key, key_size,\
64                                 (table)->normalizer, 0))) {\
65       const char *key;\
66       unsigned int key_size;\
67       grn_string_get_normalized(ctx, nstr, &key, &key_size, NULL);\
68       block\
69       grn_obj_close(ctx, nstr);\
70     }\
71   } else {\
72     block\
73   }\
74 } while (0)
75 
76 inline static grn_id
77 grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
78                        void **value, int *added);
79 inline static void
80 grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, double score,
81                             grn_rset_posinfo *pi, int dir);
82 inline static grn_id
83 grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc);
84 inline static int
85 grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value);
86 
87 static void grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj);
88 static void grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj);
89 
90 inline static void
91 grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj,
92                        grn_id *range_id, grn_obj_flags *range_flags);
93 
94 static char grn_db_key[GRN_ENV_BUFFER_SIZE];
95 
96 void
grn_db_init_from_env(void)97 grn_db_init_from_env(void)
98 {
99   grn_getenv("GRN_DB_KEY",
100              grn_db_key,
101              GRN_ENV_BUFFER_SIZE);
102 }
103 
104 inline static void
gen_pathname(const char * path,char * buffer,int fno)105 gen_pathname(const char *path, char *buffer, int fno)
106 {
107   size_t len = strlen(path);
108   grn_memcpy(buffer, path, len);
109   if (fno >= 0) {
110     buffer[len] = '.';
111     grn_itoh(fno, buffer + len + 1, 7);
112     buffer[len + 8] = '\0';
113   } else {
114     buffer[len] = '\0';
115   }
116 }
117 
118 void
grn_db_generate_pathname(grn_ctx * ctx,grn_obj * db,grn_id id,char * buffer)119 grn_db_generate_pathname(grn_ctx *ctx, grn_obj *db, grn_id id, char *buffer)
120 {
121   gen_pathname(grn_obj_get_io(ctx, db)->path, buffer, id);
122 }
123 
124 typedef struct {
125   grn_obj *ptr;
126   uint32_t lock;
127   uint32_t done;
128 } db_value;
129 
130 static const char *GRN_DB_CONFIG_PATH_FORMAT = "%s.conf";
131 
132 static grn_bool
grn_db_config_create(grn_ctx * ctx,grn_db * s,const char * path,const char * context_tag)133 grn_db_config_create(grn_ctx *ctx, grn_db *s, const char *path,
134                      const char *context_tag)
135 {
136   char *config_path;
137   char config_path_buffer[PATH_MAX];
138   uint32_t flags = GRN_OBJ_KEY_VAR_SIZE;
139 
140   if (path) {
141     grn_snprintf(config_path_buffer, PATH_MAX, PATH_MAX,
142                  GRN_DB_CONFIG_PATH_FORMAT, path);
143     config_path = config_path_buffer;
144   } else {
145     config_path = NULL;
146   }
147   s->config = grn_hash_create(ctx, config_path,
148                               GRN_CONFIG_MAX_KEY_SIZE,
149                               GRN_CONFIG_VALUE_SPACE_SIZE,
150                               flags);
151   if (!s->config) {
152     ERR(GRN_NO_MEMORY_AVAILABLE,
153         "%s failed to create data store for configuration: <%s>",
154         context_tag,
155         config_path ? config_path : "(temporary)");
156     return GRN_FALSE;
157   }
158 
159   return GRN_TRUE;
160 }
161 
162 static grn_bool
grn_db_config_open(grn_ctx * ctx,grn_db * s,const char * path)163 grn_db_config_open(grn_ctx *ctx, grn_db *s, const char *path)
164 {
165   char config_path[PATH_MAX];
166 
167   grn_snprintf(config_path, PATH_MAX, PATH_MAX, GRN_DB_CONFIG_PATH_FORMAT, path);
168   if (grn_path_exist(config_path)) {
169     s->config = grn_hash_open(ctx, config_path);
170     if (!s->config) {
171       ERR(GRN_NO_MEMORY_AVAILABLE,
172           "[db][open] failed to open data store for configuration: <%s>",
173           config_path);
174       return GRN_FALSE;
175     }
176     return GRN_TRUE;
177   } else {
178     return grn_db_config_create(ctx, s, path, "[db][open]");
179   }
180 }
181 
182 static grn_rc
grn_db_config_remove(grn_ctx * ctx,const char * path)183 grn_db_config_remove(grn_ctx *ctx, const char *path)
184 {
185   char config_path[PATH_MAX];
186 
187   grn_snprintf(config_path, PATH_MAX, PATH_MAX, GRN_DB_CONFIG_PATH_FORMAT, path);
188   return grn_hash_remove(ctx, config_path);
189 }
190 
191 grn_obj *
grn_db_create(grn_ctx * ctx,const char * path,grn_db_create_optarg * optarg)192 grn_db_create(grn_ctx *ctx, const char *path, grn_db_create_optarg *optarg)
193 {
194   grn_db *s = NULL;
195 
196   GRN_API_ENTER;
197 
198   if (path && strlen(path) > PATH_MAX - 14) {
199     ERR(GRN_INVALID_ARGUMENT, "too long path");
200     goto exit;
201   }
202 
203   s = GRN_MALLOC(sizeof(grn_db));
204   if (!s) {
205     ERR(GRN_NO_MEMORY_AVAILABLE, "grn_db alloc failed");
206     goto exit;
207   }
208 
209   CRITICAL_SECTION_INIT(s->lock);
210   grn_tiny_array_init(ctx, &s->values, sizeof(db_value),
211                       GRN_TINY_ARRAY_CLEAR|
212                       GRN_TINY_ARRAY_THREADSAFE|
213                       GRN_TINY_ARRAY_USE_MALLOC);
214   s->keys = NULL;
215   s->specs = NULL;
216   s->config = NULL;
217 
218   {
219     grn_bool use_default_db_key = GRN_TRUE;
220     grn_bool use_pat_as_db_keys = GRN_FALSE;
221     if (grn_db_key[0]) {
222       if (!strcmp(grn_db_key, "pat")) {
223         use_default_db_key = GRN_FALSE;
224         use_pat_as_db_keys = GRN_TRUE;
225       } else if (!strcmp(grn_db_key, "dat")) {
226         use_default_db_key = GRN_FALSE;
227       }
228     }
229 
230     if (use_default_db_key && !strcmp(GRN_DEFAULT_DB_KEY, "pat")) {
231       use_pat_as_db_keys = GRN_TRUE;
232     }
233     if (use_pat_as_db_keys) {
234       s->keys = (grn_obj *)grn_pat_create(ctx, path, GRN_TABLE_MAX_KEY_SIZE,
235                                           0, GRN_OBJ_KEY_VAR_SIZE);
236     } else {
237       s->keys = (grn_obj *)grn_dat_create(ctx, path, GRN_TABLE_MAX_KEY_SIZE,
238                                           0, GRN_OBJ_KEY_VAR_SIZE);
239     }
240   }
241 
242   if (!s->keys) {
243     goto exit;
244   }
245 
246   GRN_DB_OBJ_SET_TYPE(s, GRN_DB);
247   s->obj.db = (grn_obj *)s;
248   s->obj.header.domain = GRN_ID_NIL;
249   DB_OBJ(&s->obj)->range = GRN_ID_NIL;
250   /* prepare builtin classes and load builtin plugins. */
251   if (path) {
252     {
253       char specs_path[PATH_MAX];
254       gen_pathname(path, specs_path, 0);
255       s->specs = grn_ja_create(ctx, specs_path, 65536, 0);
256       if (!s->specs) {
257         ERR(GRN_NO_MEMORY_AVAILABLE,
258             "failed to create specs: <%s>", specs_path);
259         goto exit;
260       }
261     }
262     if (!grn_db_config_create(ctx, s, path, "[db][create]")) {
263       goto exit;
264     }
265     grn_ctx_use(ctx, (grn_obj *)s);
266     grn_db_init_builtin_types(ctx);
267     grn_obj_flush(ctx, (grn_obj *)s);
268     GRN_API_RETURN((grn_obj *)s);
269   } else {
270     if (!grn_db_config_create(ctx, s, NULL, "[db][create]")) {
271       goto exit;
272     }
273     grn_ctx_use(ctx, (grn_obj *)s);
274     grn_db_init_builtin_types(ctx);
275     GRN_API_RETURN((grn_obj *)s);
276   }
277 
278 exit:
279   if (s) {
280     if (s->keys) {
281       if (s->keys->header.type == GRN_TABLE_PAT_KEY) {
282         grn_pat_close(ctx, (grn_pat *)s->keys);
283         grn_pat_remove(ctx, path);
284       } else {
285         grn_dat_close(ctx, (grn_dat *)s->keys);
286         grn_dat_remove(ctx, path);
287       }
288     }
289     if (s->specs) {
290       const char *specs_path;
291       specs_path = grn_obj_path(ctx, (grn_obj *)(s->specs));
292       grn_ja_close(ctx, s->specs);
293       grn_ja_remove(ctx, specs_path);
294     }
295     grn_tiny_array_fin(&s->values);
296     CRITICAL_SECTION_FIN(s->lock);
297     GRN_FREE(s);
298   }
299 
300   GRN_API_RETURN(NULL);
301 }
302 
303 grn_obj *
grn_db_open(grn_ctx * ctx,const char * path)304 grn_db_open(grn_ctx *ctx, const char *path)
305 {
306   grn_db *s = NULL;
307 
308   GRN_API_ENTER;
309 
310   if (!path) {
311     ERR(GRN_INVALID_ARGUMENT, "[db][open] path is missing");
312     goto exit;
313   }
314 
315   if (strlen(path) > PATH_MAX - 14) {
316     ERR(GRN_INVALID_ARGUMENT, "inappropriate path");
317     goto exit;
318   }
319 
320   s = GRN_MALLOC(sizeof(grn_db));
321   if (!s) {
322     ERR(GRN_NO_MEMORY_AVAILABLE, "grn_db alloc failed");
323     goto exit;
324   }
325 
326   CRITICAL_SECTION_INIT(s->lock);
327   grn_tiny_array_init(ctx, &s->values, sizeof(db_value),
328                       GRN_TINY_ARRAY_CLEAR|
329                       GRN_TINY_ARRAY_THREADSAFE|
330                       GRN_TINY_ARRAY_USE_MALLOC);
331   s->keys = NULL;
332   s->specs = NULL;
333   s->config = NULL;
334 
335   {
336     uint32_t type = grn_io_detect_type(ctx, path);
337     switch (type) {
338     case GRN_TABLE_PAT_KEY :
339       s->keys = (grn_obj *)grn_pat_open(ctx, path);
340       break;
341     case GRN_TABLE_DAT_KEY :
342       s->keys = (grn_obj *)grn_dat_open(ctx, path);
343       break;
344     default :
345       s->keys = NULL;
346       if (ctx->rc == GRN_SUCCESS) {
347         ERR(GRN_INVALID_ARGUMENT,
348             "[db][open] invalid keys table's type: %#x", type);
349         goto exit;
350       }
351       break;
352     }
353   }
354 
355   if (!s->keys) {
356     goto exit;
357   }
358 
359   {
360     char specs_path[PATH_MAX];
361     gen_pathname(path, specs_path, 0);
362     s->specs = grn_ja_open(ctx, specs_path);
363     if (!s->specs) {
364       ERR(GRN_NO_MEMORY_AVAILABLE,
365           "[db][open] failed to open specs: <%s>", specs_path);
366       goto exit;
367     }
368   }
369   if (!grn_db_config_open(ctx, s, path)) {
370     goto exit;
371   }
372 
373   GRN_DB_OBJ_SET_TYPE(s, GRN_DB);
374   s->obj.db = (grn_obj *)s;
375   s->obj.header.domain = GRN_ID_NIL;
376   DB_OBJ(&s->obj)->range = GRN_ID_NIL;
377   grn_ctx_use(ctx, (grn_obj *)s);
378   {
379     unsigned int n_records;
380 
381     n_records = grn_table_size(ctx, (grn_obj *)s);
382 #ifdef GRN_WITH_MECAB
383     if (grn_db_init_mecab_tokenizer(ctx)) {
384       ERRCLR(ctx);
385     }
386 #endif
387     grn_db_init_builtin_tokenizers(ctx);
388     grn_db_init_builtin_normalizers(ctx);
389     grn_db_init_builtin_scorers(ctx);
390     grn_db_init_builtin_commands(ctx);
391     grn_db_init_builtin_window_functions(ctx);
392 
393     if (grn_table_size(ctx, (grn_obj *)s) > n_records) {
394       grn_obj_flush(ctx, (grn_obj *)s);
395     }
396   }
397   GRN_API_RETURN((grn_obj *)s);
398 
399 exit:
400   if (s) {
401     if (s->specs) {
402       grn_ja_close(ctx, s->specs);
403     }
404     if (s->keys) {
405       if (s->keys->header.type == GRN_TABLE_PAT_KEY) {
406         grn_pat_close(ctx, (grn_pat *)s->keys);
407       } else {
408         grn_dat_close(ctx, (grn_dat *)s->keys);
409       }
410     }
411     grn_tiny_array_fin(&s->values);
412     CRITICAL_SECTION_FIN(s->lock);
413     GRN_FREE(s);
414   }
415 
416   GRN_API_RETURN(NULL);
417 }
418 
419 static grn_id
grn_db_curr_id(grn_ctx * ctx,grn_obj * db)420 grn_db_curr_id(grn_ctx *ctx, grn_obj *db)
421 {
422   grn_id curr_id = GRN_ID_NIL;
423   grn_db *s = (grn_db *)db;
424   switch (s->keys->header.type) {
425   case GRN_TABLE_PAT_KEY :
426     curr_id = grn_pat_curr_id(ctx, (grn_pat *)s->keys);
427     break;
428   case GRN_TABLE_DAT_KEY :
429     curr_id = grn_dat_curr_id(ctx, (grn_dat *)s->keys);
430     break;
431   }
432   return curr_id;
433 }
434 
435 /* s must be validated by caller */
436 grn_rc
grn_db_close(grn_ctx * ctx,grn_obj * db)437 grn_db_close(grn_ctx *ctx, grn_obj *db)
438 {
439   grn_id id;
440   db_value *vp;
441   grn_db *s = (grn_db *)db;
442   grn_bool ctx_used_db;
443   if (!s) { return GRN_INVALID_ARGUMENT; }
444   GRN_API_ENTER;
445 
446   ctx_used_db = ctx->impl && ctx->impl->db == db;
447   if (ctx_used_db) {
448 #ifdef GRN_WITH_MECAB
449     grn_db_fin_mecab_tokenizer(ctx);
450 #endif
451     grn_ctx_loader_clear(ctx);
452     if (ctx->impl->parser) {
453       grn_expr_parser_close(ctx);
454     }
455   }
456 
457   GRN_TINY_ARRAY_EACH(&s->values, 1, grn_db_curr_id(ctx, db), id, vp, {
458     if (vp->ptr) { grn_obj_close(ctx, vp->ptr); }
459   });
460 
461   if (ctx_used_db) {
462     if (ctx->impl->values) {
463       grn_db_obj *o;
464       GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, {
465         grn_obj_close(ctx, *((grn_obj **)o));
466       });
467       grn_array_truncate(ctx, ctx->impl->values);
468     }
469   }
470 
471 /* grn_tiny_array_fin should be refined.. */
472 #ifdef WIN32
473   {
474     grn_tiny_array *a = &s->values;
475     CRITICAL_SECTION_FIN(a->lock);
476   }
477 #endif
478   grn_tiny_array_fin(&s->values);
479 
480   switch (s->keys->header.type) {
481   case GRN_TABLE_PAT_KEY :
482     grn_pat_close(ctx, (grn_pat *)s->keys);
483     break;
484   case GRN_TABLE_DAT_KEY :
485     grn_dat_close(ctx, (grn_dat *)s->keys);
486     break;
487   }
488   CRITICAL_SECTION_FIN(s->lock);
489   if (s->specs) { grn_ja_close(ctx, s->specs); }
490   grn_hash_close(ctx, s->config);
491   GRN_FREE(s);
492 
493   if (ctx_used_db) {
494     grn_cache *cache;
495     cache = grn_cache_current_get(ctx);
496     if (cache) {
497       grn_cache_expire(cache, -1);
498     }
499     ctx->impl->db = NULL;
500   }
501 
502   GRN_API_RETURN(GRN_SUCCESS);
503 }
504 
505 grn_obj *
grn_ctx_get(grn_ctx * ctx,const char * name,int name_size)506 grn_ctx_get(grn_ctx *ctx, const char *name, int name_size)
507 {
508   grn_obj *obj = NULL;
509   grn_obj *db;
510   if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
511     return NULL;
512   }
513   GRN_API_ENTER;
514   if (GRN_DB_P(db)) {
515     grn_db *s = (grn_db *)db;
516     grn_obj *alias_table = NULL;
517     grn_obj *alias_column = NULL;
518     grn_obj alias_name_buffer;
519 
520     if (name_size < 0) {
521       name_size = strlen(name);
522     }
523     GRN_TEXT_INIT(&alias_name_buffer, 0);
524     while (GRN_TRUE) {
525       grn_id id;
526 
527       id = grn_table_get(ctx, s->keys, name, name_size);
528       if (id) {
529         obj = grn_ctx_at(ctx, id);
530         break;
531       }
532 
533       if (!alias_column) {
534         grn_id alias_column_id;
535         const char *alias_column_name;
536         uint32_t alias_column_name_size;
537 
538         grn_config_get(ctx,
539                        "alias.column", -1,
540                        &alias_column_name, &alias_column_name_size);
541         if (!alias_column_name) {
542           break;
543         }
544         alias_column_id = grn_table_get(ctx,
545                                         s->keys,
546                                         alias_column_name,
547                                         alias_column_name_size);
548         if (!alias_column_id) {
549           break;
550         }
551         alias_column = grn_ctx_at(ctx, alias_column_id);
552         if (alias_column->header.type != GRN_COLUMN_VAR_SIZE) {
553           break;
554         }
555         if (alias_column->header.flags & GRN_OBJ_VECTOR) {
556           break;
557         }
558         if (DB_OBJ(alias_column)->range != GRN_DB_SHORT_TEXT) {
559           break;
560         }
561         alias_table = grn_ctx_at(ctx, alias_column->header.domain);
562         if (alias_table->header.type == GRN_TABLE_NO_KEY) {
563           break;
564         }
565       }
566 
567       {
568         grn_id alias_id;
569         alias_id = grn_table_get(ctx, alias_table, name, name_size);
570         if (!alias_id) {
571           break;
572         }
573         GRN_BULK_REWIND(&alias_name_buffer);
574         grn_obj_get_value(ctx, alias_column, alias_id, &alias_name_buffer);
575         name = GRN_TEXT_VALUE(&alias_name_buffer);
576         name_size = GRN_TEXT_LEN(&alias_name_buffer);
577       }
578     }
579     GRN_OBJ_FIN(ctx, &alias_name_buffer);
580   }
581   GRN_API_RETURN(obj);
582 }
583 
584 grn_obj *
grn_ctx_db(grn_ctx * ctx)585 grn_ctx_db(grn_ctx *ctx)
586 {
587   return (ctx && ctx->impl) ? ctx->impl->db : NULL;
588 }
589 
590 grn_obj *
grn_db_keys(grn_obj * s)591 grn_db_keys(grn_obj *s)
592 {
593   return (grn_obj *)(((grn_db *)s)->keys);
594 }
595 
596 uint32_t
grn_obj_get_last_modified(grn_ctx * ctx,grn_obj * obj)597 grn_obj_get_last_modified(grn_ctx *ctx, grn_obj *obj)
598 {
599   if (!obj) {
600     return 0;
601   }
602 
603   return grn_obj_get_io(ctx, obj)->header->last_modified;
604 }
605 
606 grn_bool
grn_obj_is_dirty(grn_ctx * ctx,grn_obj * obj)607 grn_obj_is_dirty(grn_ctx *ctx, grn_obj *obj)
608 {
609   if (!obj) {
610     return GRN_FALSE;
611   }
612 
613   switch (obj->header.type) {
614   case GRN_DB :
615     return grn_db_is_dirty(ctx, obj);
616   case GRN_TABLE_PAT_KEY :
617     return grn_pat_is_dirty(ctx, (grn_pat *)obj);
618   case GRN_TABLE_DAT_KEY :
619     return grn_dat_is_dirty(ctx, (grn_dat *)obj);
620   default :
621     return GRN_FALSE;
622   }
623 }
624 
625 uint32_t
grn_db_get_last_modified(grn_ctx * ctx,grn_obj * db)626 grn_db_get_last_modified(grn_ctx *ctx, grn_obj *db)
627 {
628   return grn_obj_get_last_modified(ctx, db);
629 }
630 
631 grn_bool
grn_db_is_dirty(grn_ctx * ctx,grn_obj * db)632 grn_db_is_dirty(grn_ctx *ctx, grn_obj *db)
633 {
634   grn_obj *keys;
635 
636   if (!db) {
637     return GRN_FALSE;
638   }
639 
640   keys = ((grn_db *)db)->keys;
641   return grn_obj_is_dirty(ctx, keys);
642 }
643 
644 static grn_rc
grn_db_dirty(grn_ctx * ctx,grn_obj * db)645 grn_db_dirty(grn_ctx *ctx, grn_obj *db)
646 {
647   grn_obj *keys;
648 
649   if (!db) {
650     return GRN_SUCCESS;
651   }
652 
653   keys = ((grn_db *)db)->keys;
654   switch (keys->header.type) {
655   case GRN_TABLE_PAT_KEY :
656     return grn_pat_dirty(ctx, (grn_pat *)keys);
657   case GRN_TABLE_DAT_KEY :
658     return grn_dat_dirty(ctx, (grn_dat *)keys);
659   default :
660     return GRN_SUCCESS;
661   }
662 }
663 
664 static grn_rc
grn_db_clean(grn_ctx * ctx,grn_obj * db)665 grn_db_clean(grn_ctx *ctx, grn_obj *db)
666 {
667   grn_obj *keys;
668 
669   if (!db) {
670     return GRN_SUCCESS;
671   }
672 
673   keys = ((grn_db *)db)->keys;
674   switch (keys->header.type) {
675   case GRN_TABLE_PAT_KEY :
676     return grn_pat_clean(ctx, (grn_pat *)keys);
677   case GRN_TABLE_DAT_KEY :
678     return grn_dat_clean(ctx, (grn_dat *)keys);
679   default :
680     return GRN_SUCCESS;
681   }
682 }
683 
684 static grn_rc
grn_db_clear_dirty(grn_ctx * ctx,grn_obj * db)685 grn_db_clear_dirty(grn_ctx *ctx, grn_obj *db)
686 {
687   grn_obj *keys;
688 
689   if (!db) {
690     return GRN_SUCCESS;
691   }
692 
693   keys = ((grn_db *)db)->keys;
694   switch (keys->header.type) {
695   case GRN_TABLE_PAT_KEY :
696     return grn_pat_clear_dirty(ctx, (grn_pat *)keys);
697   case GRN_TABLE_DAT_KEY :
698     return grn_dat_clear_dirty(ctx, (grn_dat *)keys);
699   default :
700     return GRN_SUCCESS;
701   }
702 }
703 
704 void
grn_db_touch(grn_ctx * ctx,grn_obj * s)705 grn_db_touch(grn_ctx *ctx, grn_obj *s)
706 {
707   grn_obj_touch(ctx, s, NULL);
708 }
709 
710 grn_bool
grn_obj_is_corrupt(grn_ctx * ctx,grn_obj * obj)711 grn_obj_is_corrupt(grn_ctx *ctx, grn_obj *obj)
712 {
713   grn_bool is_corrupt = GRN_FALSE;
714 
715   GRN_API_ENTER;
716 
717   if (!obj) {
718     ERR(GRN_INVALID_ARGUMENT, "[object][corrupt] object must not be NULL");
719     GRN_API_RETURN(GRN_FALSE);
720   }
721 
722   switch (obj->header.type) {
723   case GRN_DB :
724     is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
725     if (!is_corrupt) {
726       is_corrupt = grn_io_is_corrupt(ctx, ((grn_db *)obj)->specs->io);
727     }
728     if (!is_corrupt) {
729       is_corrupt = grn_io_is_corrupt(ctx, ((grn_db *)obj)->config->io);
730     }
731     break;
732   case GRN_TABLE_HASH_KEY :
733   case GRN_TABLE_PAT_KEY :
734     is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
735     break;
736   case GRN_TABLE_DAT_KEY :
737     is_corrupt = grn_dat_is_corrupt(ctx, (grn_dat *)obj);
738     break;
739   case GRN_COLUMN_FIX_SIZE :
740   case GRN_COLUMN_VAR_SIZE :
741     is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
742     break;
743   case GRN_COLUMN_INDEX :
744     is_corrupt = grn_io_is_corrupt(ctx, ((grn_ii *)obj)->seg);
745     if (!is_corrupt) {
746       is_corrupt = grn_io_is_corrupt(ctx, ((grn_ii *)obj)->chunk);
747     }
748     break;
749   default :
750     break;
751   }
752 
753   GRN_API_RETURN(is_corrupt);
754 }
755 
756 #define IS_TEMP(obj) (DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)
757 
758 static inline void
grn_obj_touch_db(grn_ctx * ctx,grn_obj * obj,grn_timeval * tv)759 grn_obj_touch_db(grn_ctx *ctx, grn_obj *obj, grn_timeval *tv)
760 {
761   grn_obj_get_io(ctx, obj)->header->last_modified = tv->tv_sec;
762   grn_db_dirty(ctx, obj);
763 }
764 
765 void
grn_obj_touch(grn_ctx * ctx,grn_obj * obj,grn_timeval * tv)766 grn_obj_touch(grn_ctx *ctx, grn_obj *obj, grn_timeval *tv)
767 {
768   grn_timeval tv_;
769   if (!tv) {
770     grn_timeval_now(ctx, &tv_);
771     tv = &tv_;
772   }
773   if (obj) {
774     switch (obj->header.type) {
775     case GRN_DB :
776       grn_obj_touch_db(ctx, obj, tv);
777       break;
778     case GRN_TABLE_HASH_KEY :
779     case GRN_TABLE_PAT_KEY :
780     case GRN_TABLE_DAT_KEY :
781     case GRN_TABLE_NO_KEY :
782     case GRN_COLUMN_VAR_SIZE :
783     case GRN_COLUMN_FIX_SIZE :
784     case GRN_COLUMN_INDEX :
785       if (!IS_TEMP(obj)) {
786         grn_obj_get_io(ctx, obj)->header->last_modified = tv->tv_sec;
787         grn_obj_touch(ctx, DB_OBJ(obj)->db, tv);
788       }
789       break;
790     }
791   }
792 }
793 
794 grn_rc
grn_db_check_name(grn_ctx * ctx,const char * name,unsigned int name_size)795 grn_db_check_name(grn_ctx *ctx, const char *name, unsigned int name_size)
796 {
797   int len;
798   const char *name_end = name + name_size;
799   if (name_size > 0 &&
800       *name == GRN_DB_PSEUDO_COLUMN_PREFIX) {
801     return GRN_INVALID_ARGUMENT;
802   }
803   while (name < name_end) {
804     char c = *name;
805     if ((unsigned int)((c | 0x20) - 'a') >= 26u &&
806         (unsigned int)(c - '0') >= 10u &&
807         c != '_' &&
808         c != '-' &&
809         c != '#' &&
810         c != '@') {
811       return GRN_INVALID_ARGUMENT;
812     }
813     if (!(len = grn_charlen(ctx, name, name_end))) { break; }
814     name += len;
815   }
816   return GRN_SUCCESS;
817 }
818 
819 static grn_obj *
grn_type_open(grn_ctx * ctx,grn_obj_spec * spec)820 grn_type_open(grn_ctx *ctx, grn_obj_spec *spec)
821 {
822   struct _grn_type *res;
823   res = GRN_MALLOC(sizeof(struct _grn_type));
824   if (res) {
825     GRN_DB_OBJ_SET_TYPE(res, GRN_TYPE);
826     res->obj.header = spec->header;
827     GRN_TYPE_SIZE(&res->obj) = GRN_TYPE_SIZE(spec);
828   }
829   return (grn_obj *)res;
830 }
831 
832 grn_obj *
grn_proc_create(grn_ctx * ctx,const char * name,int name_size,grn_proc_type type,grn_proc_func * init,grn_proc_func * next,grn_proc_func * fin,unsigned int nvars,grn_expr_var * vars)833 grn_proc_create(grn_ctx *ctx, const char *name, int name_size, grn_proc_type type,
834                 grn_proc_func *init, grn_proc_func *next, grn_proc_func *fin,
835                 unsigned int nvars, grn_expr_var *vars)
836 {
837   grn_proc *res = NULL;
838   grn_id id = GRN_ID_NIL;
839   grn_id range = GRN_ID_NIL;
840   int added = 0;
841   grn_obj *db;
842   const char *path;
843   if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
844     ERR(GRN_INVALID_ARGUMENT, "db not initialized");
845     return NULL;
846   }
847   GRN_API_ENTER;
848   path = ctx->impl->plugin_path;
849   if (path) {
850     range = grn_plugin_reference(ctx, path);
851   }
852   if (name_size < 0) {
853     name_size = strlen(name);
854   }
855   if (grn_db_check_name(ctx, name, name_size)) {
856     GRN_DB_CHECK_NAME_ERR("[proc][create]", name, name_size);
857     GRN_API_RETURN(NULL);
858   }
859   if (!GRN_DB_P(db)) {
860     ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
861     GRN_API_RETURN(NULL);
862   }
863   if (name && name_size) {
864     grn_db *s = (grn_db *)db;
865     if (!(id = grn_table_get(ctx, s->keys, name, name_size))) {
866       if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
867         ERR(GRN_NO_MEMORY_AVAILABLE, "grn_table_add failed");
868         GRN_API_RETURN(NULL);
869       }
870     }
871     if (!added) {
872       db_value *vp;
873       if ((vp = grn_tiny_array_at(&s->values, id)) && (res = (grn_proc *)vp->ptr)) {
874         /* TODO: Do more robust check. */
875         if (res->funcs[PROC_INIT] ||
876             res->funcs[PROC_NEXT] ||
877             res->funcs[PROC_FIN]) {
878           ERR(GRN_INVALID_ARGUMENT, "already used name");
879           GRN_API_RETURN(NULL);
880         }
881         if (range != GRN_ID_NIL) {
882           grn_plugin_close(ctx, range);
883         }
884         GRN_API_RETURN((grn_obj *)res);
885       } else {
886         added = 1;
887       }
888     }
889   } else if (ctx->impl && ctx->impl->values) {
890     id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
891     added = 1;
892   }
893   if (!res) { res = GRN_MALLOCN(grn_proc, 1); }
894   if (res) {
895     GRN_DB_OBJ_SET_TYPE(res, GRN_PROC);
896     res->obj.db = db;
897     res->obj.id = id;
898     res->obj.header.domain = GRN_ID_NIL;
899     res->obj.header.flags = path ? GRN_OBJ_CUSTOM_NAME : 0;
900     res->obj.range = range;
901     res->type = type;
902     res->funcs[PROC_INIT] = init;
903     res->funcs[PROC_NEXT] = next;
904     res->funcs[PROC_FIN] = fin;
905     memset(&(res->callbacks), 0, sizeof(res->callbacks));
906     res->callbacks.function.selector_op = GRN_OP_NOP;
907     res->callbacks.function.is_stable = GRN_TRUE;
908     GRN_TEXT_INIT(&res->name_buf, 0);
909     res->vars = NULL;
910     res->nvars = 0;
911     if (added) {
912       if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
913         // grn_obj_delete(ctx, db, id);
914         GRN_FREE(res);
915         GRN_API_RETURN(NULL);
916       }
917     }
918     while (nvars--) {
919       grn_obj *v = grn_expr_add_var(ctx, (grn_obj *)res, vars->name, vars->name_size);
920       GRN_OBJ_INIT(v, vars->value.header.type, 0, vars->value.header.domain);
921       GRN_TEXT_PUT(ctx, v, GRN_TEXT_VALUE(&vars->value), GRN_TEXT_LEN(&vars->value));
922       vars++;
923     }
924   }
925   GRN_API_RETURN((grn_obj *)res);
926 }
927 
928 /* grn_table */
929 
930 static void
calc_rec_size(grn_table_flags flags,uint32_t max_n_subrecs,uint32_t range_size,uint32_t additional_value_size,uint8_t * subrec_size,uint8_t * subrec_offset,uint32_t * key_size,uint32_t * value_size)931 calc_rec_size(grn_table_flags flags, uint32_t max_n_subrecs, uint32_t range_size,
932               uint32_t additional_value_size,
933               uint8_t *subrec_size, uint8_t *subrec_offset,
934               uint32_t *key_size, uint32_t *value_size)
935 {
936   *subrec_size = 0;
937   *subrec_offset = 0;
938   if (flags & GRN_OBJ_WITH_SUBREC) {
939     switch (flags & GRN_OBJ_UNIT_MASK) {
940     case GRN_OBJ_UNIT_DOCUMENT_NONE :
941       break;
942     case GRN_OBJ_UNIT_DOCUMENT_SECTION :
943       *subrec_offset = sizeof(grn_id);
944       *subrec_size = sizeof(uint32_t);
945       break;
946     case GRN_OBJ_UNIT_DOCUMENT_POSITION :
947       *subrec_offset = sizeof(grn_id);
948       *subrec_size = sizeof(uint32_t) + sizeof(uint32_t);
949       break;
950     case GRN_OBJ_UNIT_SECTION_NONE :
951       *key_size += sizeof(uint32_t);
952       break;
953     case GRN_OBJ_UNIT_SECTION_POSITION :
954       *key_size += sizeof(uint32_t);
955       *subrec_offset = sizeof(grn_id) + sizeof(uint32_t);
956       *subrec_size = sizeof(uint32_t);
957       break;
958     case GRN_OBJ_UNIT_POSITION_NONE :
959       *key_size += sizeof(uint32_t) + sizeof(uint32_t);
960       break;
961     case GRN_OBJ_UNIT_USERDEF_DOCUMENT :
962       *subrec_size = range_size;
963       break;
964     case GRN_OBJ_UNIT_USERDEF_SECTION :
965       *subrec_size = range_size + sizeof(uint32_t);
966       break;
967     case GRN_OBJ_UNIT_USERDEF_POSITION :
968       *subrec_size = range_size + sizeof(uint32_t) + sizeof(uint32_t);
969       break;
970     }
971     *value_size = (uintptr_t)GRN_RSET_SUBRECS_NTH((((grn_rset_recinfo *)0)->subrecs),
972                                                   *subrec_size, max_n_subrecs);
973   } else {
974     *value_size = range_size;
975   }
976   *value_size += additional_value_size;
977 }
978 
979 static grn_rc _grn_obj_remove(grn_ctx *ctx, grn_obj *obj, grn_bool dependent);
980 
981 static grn_rc
grn_table_create_validate(grn_ctx * ctx,const char * name,unsigned int name_size,const char * path,grn_table_flags flags,grn_obj * key_type,grn_obj * value_type)982 grn_table_create_validate(grn_ctx *ctx, const char *name, unsigned int name_size,
983                           const char *path, grn_table_flags flags,
984                           grn_obj *key_type, grn_obj *value_type)
985 {
986   grn_table_flags table_type;
987   const char *table_type_name = NULL;
988 
989   table_type = (flags & GRN_OBJ_TABLE_TYPE_MASK);
990   switch (table_type) {
991   case GRN_OBJ_TABLE_HASH_KEY :
992     table_type_name = "TABLE_HASH_KEY";
993     break;
994   case GRN_OBJ_TABLE_PAT_KEY :
995     table_type_name = "TABLE_PAT_KEY";
996     break;
997   case GRN_OBJ_TABLE_DAT_KEY :
998     table_type_name = "TABLE_DAT_KEY";
999     break;
1000   case GRN_OBJ_TABLE_NO_KEY :
1001     table_type_name = "TABLE_NO_KEY";
1002     break;
1003   default :
1004     table_type_name = "unknown";
1005     break;
1006   }
1007 
1008   if (!key_type && table_type != GRN_OBJ_TABLE_NO_KEY &&
1009       !(flags & GRN_OBJ_KEY_VAR_SIZE)) {
1010     ERR(GRN_INVALID_ARGUMENT,
1011         "[table][create] "
1012         "key type is required for TABLE_HASH_KEY, TABLE_PAT_KEY or "
1013         "TABLE_DAT_KEY: <%.*s>", name_size, name);
1014     return ctx->rc;
1015   }
1016 
1017   if (key_type && table_type == GRN_OBJ_TABLE_NO_KEY) {
1018     int key_name_size;
1019     char key_name[GRN_TABLE_MAX_KEY_SIZE];
1020     key_name_size = grn_obj_name(ctx, key_type, key_name,
1021                                  GRN_TABLE_MAX_KEY_SIZE);
1022     ERR(GRN_INVALID_ARGUMENT,
1023         "[table][create] "
1024         "key isn't available for TABLE_NO_KEY table: <%.*s> (%.*s)",
1025         name_size, name, key_name_size, key_name);
1026     return ctx->rc;
1027   }
1028 
1029   if ((flags & GRN_OBJ_KEY_WITH_SIS) &&
1030       table_type != GRN_OBJ_TABLE_PAT_KEY) {
1031     ERR(GRN_INVALID_ARGUMENT,
1032         "[table][create] "
1033         "key with SIS is available only for TABLE_PAT_KEY table: "
1034         "<%.*s>(%s)",
1035         name_size, name,
1036         table_type_name);
1037     return ctx->rc;
1038   }
1039 
1040   if ((flags & GRN_OBJ_KEY_NORMALIZE) &&
1041       table_type == GRN_OBJ_TABLE_NO_KEY) {
1042     ERR(GRN_INVALID_ARGUMENT,
1043         "[table][create] "
1044         "key normalization isn't available for TABLE_NO_KEY table: <%.*s>",
1045         name_size, name);
1046     return ctx->rc;
1047   }
1048 
1049   if ((flags & GRN_OBJ_KEY_LARGE) &&
1050       table_type != GRN_OBJ_TABLE_HASH_KEY) {
1051     ERR(GRN_INVALID_ARGUMENT,
1052         "[table][create] "
1053         "large key support is available only for TABLE_HASH_KEY key table: "
1054         "<%.*s>(%s)",
1055         name_size, name,
1056         table_type_name);
1057     return ctx->rc;
1058   }
1059 
1060   return ctx->rc;
1061 }
1062 
1063 static grn_obj *
grn_table_create_with_max_n_subrecs(grn_ctx * ctx,const char * name,unsigned int name_size,const char * path,grn_table_flags flags,grn_obj * key_type,grn_obj * value_type,uint32_t max_n_subrecs,uint32_t additional_value_size)1064 grn_table_create_with_max_n_subrecs(grn_ctx *ctx, const char *name,
1065                                     unsigned int name_size, const char *path,
1066                                     grn_table_flags flags, grn_obj *key_type,
1067                                     grn_obj *value_type,
1068                                     uint32_t max_n_subrecs,
1069                                     uint32_t additional_value_size)
1070 {
1071   grn_id id;
1072   grn_id domain = GRN_ID_NIL, range = GRN_ID_NIL;
1073   uint32_t key_size, value_size = 0, range_size = 0;
1074   uint8_t subrec_size, subrec_offset;
1075   grn_obj *res = NULL;
1076   grn_obj *db;
1077   char buffer[PATH_MAX];
1078   if (!ctx->impl || !(db = ctx->impl->db)) {
1079     ERR(GRN_INVALID_ARGUMENT, "[table][create] db not initialized");
1080     return NULL;
1081   }
1082   if (grn_db_check_name(ctx, name, name_size)) {
1083     GRN_DB_CHECK_NAME_ERR("[table][create]", name, name_size);
1084     return NULL;
1085   }
1086   if (!GRN_DB_P(db)) {
1087     ERR(GRN_INVALID_ARGUMENT, "[table][create] invalid db assigned");
1088     return NULL;
1089   }
1090   if (grn_table_create_validate(ctx, name, name_size, path, flags,
1091                                 key_type, value_type)) {
1092     return NULL;
1093   }
1094   if (key_type) {
1095     domain = DB_OBJ(key_type)->id;
1096     switch (key_type->header.type) {
1097     case GRN_TYPE :
1098       {
1099         grn_db_obj *t = (grn_db_obj *)key_type;
1100         flags |= t->header.flags;
1101         key_size = GRN_TYPE_SIZE(t);
1102         if (key_size > GRN_TABLE_MAX_KEY_SIZE) {
1103           int type_name_size;
1104           char type_name[GRN_TABLE_MAX_KEY_SIZE];
1105           type_name_size = grn_obj_name(ctx, key_type, type_name,
1106                                         GRN_TABLE_MAX_KEY_SIZE);
1107           ERR(GRN_INVALID_ARGUMENT,
1108               "[table][create] key size too big: <%.*s> <%.*s>(%u) (max:%u)",
1109               name_size, name,
1110               type_name_size, type_name,
1111               key_size, GRN_TABLE_MAX_KEY_SIZE);
1112           return NULL;
1113         }
1114       }
1115       break;
1116     case GRN_TABLE_HASH_KEY :
1117     case GRN_TABLE_PAT_KEY :
1118     case GRN_TABLE_DAT_KEY :
1119     case GRN_TABLE_NO_KEY :
1120       key_size = sizeof(grn_id);
1121       break;
1122     default :
1123       {
1124         int key_name_size;
1125         char key_name[GRN_TABLE_MAX_KEY_SIZE];
1126         key_name_size = grn_obj_name(ctx, key_type, key_name,
1127                                      GRN_TABLE_MAX_KEY_SIZE);
1128         ERR(GRN_INVALID_ARGUMENT,
1129             "[table][create] key type must be type or table: <%.*s> (%.*s)",
1130             name_size, name, key_name_size, key_name);
1131         return NULL;
1132       }
1133       break;
1134     }
1135   } else {
1136     key_size = (flags & GRN_OBJ_KEY_VAR_SIZE) ? GRN_TABLE_MAX_KEY_SIZE : sizeof(grn_id);
1137   }
1138   if (value_type) {
1139     range = DB_OBJ(value_type)->id;
1140     switch (value_type->header.type) {
1141     case GRN_TYPE :
1142       {
1143         grn_db_obj *t = (grn_db_obj *)value_type;
1144         if (t->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1145           int type_name_size;
1146           char type_name[GRN_TABLE_MAX_KEY_SIZE];
1147           type_name_size = grn_obj_name(ctx, value_type, type_name,
1148                                         GRN_TABLE_MAX_KEY_SIZE);
1149           ERR(GRN_INVALID_ARGUMENT,
1150               "[table][create] value type must be fixed size: <%.*s> (%.*s)",
1151               name_size, name, type_name_size, type_name);
1152           return NULL;
1153         }
1154         range_size = GRN_TYPE_SIZE(t);
1155       }
1156       break;
1157     case GRN_TABLE_HASH_KEY :
1158     case GRN_TABLE_PAT_KEY :
1159     case GRN_TABLE_DAT_KEY :
1160     case GRN_TABLE_NO_KEY :
1161       range_size = sizeof(grn_id);
1162       break;
1163     default :
1164       {
1165         int value_name_size;
1166         char value_name[GRN_TABLE_MAX_KEY_SIZE];
1167         value_name_size = grn_obj_name(ctx, value_type, value_name,
1168                                        GRN_TABLE_MAX_KEY_SIZE);
1169         ERR(GRN_INVALID_ARGUMENT,
1170             "[table][create] value type must be type or table: <%.*s> (%.*s)",
1171             name_size, name, value_name_size, value_name);
1172         return NULL;
1173       }
1174       break;
1175     }
1176   }
1177 
1178   id = grn_obj_register(ctx, db, name, name_size);
1179   if (ERRP(ctx, GRN_ERROR)) { return NULL;  }
1180   if (GRN_OBJ_PERSISTENT & flags) {
1181     GRN_LOG(ctx, GRN_LOG_NOTICE,
1182             "DDL:%u:table_create %.*s", id, name_size, name);
1183     if (!path) {
1184       if (GRN_DB_PERSISTENT_P(db)) {
1185         grn_db_generate_pathname(ctx, db, id, buffer);
1186         path = buffer;
1187       } else {
1188         ERR(GRN_INVALID_ARGUMENT, "path not assigned for persistent table");
1189         grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1190         return NULL;
1191       }
1192     } else {
1193       flags |= GRN_OBJ_CUSTOM_NAME;
1194     }
1195   } else {
1196     if (path) {
1197       ERR(GRN_INVALID_ARGUMENT, "path assigned for temporary table");
1198       grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1199       return NULL;
1200     }
1201     if (GRN_DB_PERSISTENT_P(db) && name && name_size) {
1202       ERR(GRN_INVALID_ARGUMENT, "name assigned for temporary table");
1203       grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1204       return NULL;
1205     }
1206   }
1207   calc_rec_size(flags, max_n_subrecs, range_size, additional_value_size,
1208                 &subrec_size, &subrec_offset, &key_size, &value_size);
1209   switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
1210   case GRN_OBJ_TABLE_HASH_KEY :
1211     res = (grn_obj *)grn_hash_create(ctx, path, key_size, value_size, flags);
1212     break;
1213   case GRN_OBJ_TABLE_PAT_KEY :
1214     res = (grn_obj *)grn_pat_create(ctx, path, key_size, value_size, flags);
1215     break;
1216   case GRN_OBJ_TABLE_DAT_KEY :
1217     res = (grn_obj *)grn_dat_create(ctx, path, key_size, value_size, flags);
1218     break;
1219   case GRN_OBJ_TABLE_NO_KEY :
1220     domain = range;
1221     res = (grn_obj *)grn_array_create(ctx, path, value_size, flags);
1222     break;
1223   }
1224   if (res) {
1225     DB_OBJ(res)->header.impl_flags = 0;
1226     DB_OBJ(res)->header.domain = domain;
1227     DB_OBJ(res)->range = range;
1228     DB_OBJ(res)->max_n_subrecs = max_n_subrecs;
1229     DB_OBJ(res)->subrec_size = subrec_size;
1230     DB_OBJ(res)->subrec_offset = subrec_offset;
1231     DB_OBJ(res)->flags.group = 0;
1232     if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
1233       _grn_obj_remove(ctx, res, GRN_FALSE);
1234       res = NULL;
1235     }
1236   } else {
1237     grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1238   }
1239   return res;
1240 }
1241 
1242 grn_obj *
grn_table_create(grn_ctx * ctx,const char * name,unsigned int name_size,const char * path,grn_table_flags flags,grn_obj * key_type,grn_obj * value_type)1243 grn_table_create(grn_ctx *ctx, const char *name, unsigned int name_size,
1244                  const char *path, grn_table_flags flags,
1245                  grn_obj *key_type, grn_obj *value_type)
1246 {
1247   grn_obj *res;
1248   GRN_API_ENTER;
1249   res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
1250                                             flags, key_type, value_type,
1251                                             0, 0);
1252   GRN_API_RETURN(res);
1253 }
1254 
1255 grn_obj *
grn_table_create_for_group(grn_ctx * ctx,const char * name,unsigned int name_size,const char * path,grn_obj * group_key,grn_obj * value_type,unsigned int max_n_subrecs)1256 grn_table_create_for_group(grn_ctx *ctx, const char *name,
1257                            unsigned int name_size, const char *path,
1258                            grn_obj *group_key, grn_obj *value_type,
1259                            unsigned int max_n_subrecs)
1260 {
1261   grn_obj *res = NULL;
1262   GRN_API_ENTER;
1263   if (group_key) {
1264     grn_obj *key_type;
1265     key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, group_key));
1266     if (key_type) {
1267       res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
1268                                                 GRN_TABLE_HASH_KEY|
1269                                                 GRN_OBJ_WITH_SUBREC|
1270                                                 GRN_OBJ_UNIT_USERDEF_DOCUMENT,
1271                                                 key_type, value_type,
1272                                                 max_n_subrecs, 0);
1273       grn_obj_unlink(ctx, key_type);
1274     }
1275   } else {
1276     res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
1277                                               GRN_TABLE_HASH_KEY|
1278                                               GRN_OBJ_KEY_VAR_SIZE|
1279                                               GRN_OBJ_WITH_SUBREC|
1280                                               GRN_OBJ_UNIT_USERDEF_DOCUMENT,
1281                                               NULL, value_type,
1282                                               max_n_subrecs, 0);
1283   }
1284   GRN_API_RETURN(res);
1285 }
1286 
1287 unsigned int
grn_table_get_subrecs(grn_ctx * ctx,grn_obj * table,grn_id id,grn_id * subrecbuf,int * scorebuf,int buf_size)1288 grn_table_get_subrecs(grn_ctx *ctx, grn_obj *table, grn_id id,
1289                       grn_id *subrecbuf, int *scorebuf, int buf_size)
1290 {
1291   unsigned int count = 0;
1292   GRN_API_ENTER;
1293   if (GRN_OBJ_TABLEP(table)) {
1294     uint32_t value_size;
1295     grn_rset_recinfo *ri;
1296     uint32_t subrec_size = DB_OBJ(table)->subrec_size;
1297     uint32_t max_n_subrecs = DB_OBJ(table)->max_n_subrecs;
1298     if (subrec_size < sizeof(grn_id)) { goto exit; }
1299     if (!max_n_subrecs) { goto exit; }
1300     ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, table, id, &value_size);
1301     if (ri) {
1302       byte *psubrec = (byte *)ri->subrecs;
1303       uint32_t n_subrecs = (uint32_t)GRN_RSET_N_SUBRECS(ri);
1304       uint32_t limit = value_size / (GRN_RSET_SCORE_SIZE + subrec_size);
1305       if (limit > buf_size) {
1306         limit = buf_size;
1307       }
1308       if (limit > n_subrecs) {
1309         limit = n_subrecs;
1310       }
1311       if (limit > max_n_subrecs) {
1312         limit = max_n_subrecs;
1313       }
1314       for (; count < limit; count++) {
1315         if (scorebuf) {
1316           scorebuf[count] = *((double *)psubrec);
1317         }
1318         psubrec += GRN_RSET_SCORE_SIZE;
1319         if (subrecbuf) {
1320           subrecbuf[count] = *((grn_id *)psubrec);
1321         }
1322         psubrec += subrec_size;
1323       }
1324     }
1325   }
1326 exit :
1327   GRN_API_RETURN(count);
1328 }
1329 
1330 grn_obj *
grn_table_open(grn_ctx * ctx,const char * name,unsigned int name_size,const char * path)1331 grn_table_open(grn_ctx *ctx, const char *name, unsigned int name_size, const char *path)
1332 {
1333   grn_obj *db;
1334   if (!ctx->impl || !(db = ctx->impl->db)) {
1335     ERR(GRN_INVALID_ARGUMENT, "db not initialized");
1336     return NULL;
1337   }
1338   GRN_API_ENTER;
1339   if (!GRN_DB_P(db)) {
1340     ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
1341     GRN_API_RETURN(NULL);
1342   } else {
1343     grn_obj *res = grn_ctx_get(ctx, name, name_size);
1344     if (res) {
1345       const char *path2 = grn_obj_path(ctx, res);
1346       if (path && (!path2 || strcmp(path, path2))) {
1347         ERR(GRN_INVALID_ARGUMENT, "path unmatch");
1348         GRN_API_RETURN(NULL);
1349       }
1350     } else if (path) {
1351       uint32_t type = grn_io_detect_type(ctx, path);
1352       if (!type) { GRN_API_RETURN(NULL); }
1353       switch (type) {
1354       case GRN_TABLE_HASH_KEY :
1355         res = (grn_obj *)grn_hash_open(ctx, path);
1356         break;
1357       case GRN_TABLE_PAT_KEY :
1358         res = (grn_obj *)grn_pat_open(ctx, path);
1359         break;
1360       case GRN_TABLE_DAT_KEY :
1361         res = (grn_obj *)grn_dat_open(ctx, path);
1362         break;
1363       case GRN_TABLE_NO_KEY :
1364         res = (grn_obj *)grn_array_open(ctx, path);
1365         break;
1366       }
1367       if (res) {
1368         grn_id id = grn_obj_register(ctx, db, name, name_size);
1369         res->header.flags |= GRN_OBJ_CUSTOM_NAME;
1370         res->header.domain = GRN_ID_NIL; /* unknown */
1371         DB_OBJ(res)->range = GRN_ID_NIL; /* unknown */
1372         grn_db_obj_init(ctx, db, id, DB_OBJ(res));
1373       }
1374     } else {
1375       ERR(GRN_INVALID_ARGUMENT, "path is missing");
1376     }
1377     GRN_API_RETURN(res);
1378   }
1379 }
1380 
1381 grn_id
grn_table_lcp_search(grn_ctx * ctx,grn_obj * table,const void * key,unsigned int key_size)1382 grn_table_lcp_search(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
1383 {
1384   grn_id id = GRN_ID_NIL;
1385   GRN_API_ENTER;
1386   switch (table->header.type) {
1387   case GRN_TABLE_PAT_KEY :
1388     {
1389       grn_pat *pat = (grn_pat *)table;
1390       WITH_NORMALIZE(pat, key, key_size, {
1391         id = grn_pat_lcp_search(ctx, pat, key, key_size);
1392       });
1393     }
1394     break;
1395   case GRN_TABLE_DAT_KEY :
1396     {
1397       grn_dat *dat = (grn_dat *)table;
1398       WITH_NORMALIZE(dat, key, key_size, {
1399         id = grn_dat_lcp_search(ctx, dat, key, key_size);
1400       });
1401     }
1402     break;
1403   case GRN_TABLE_HASH_KEY :
1404     {
1405       grn_hash *hash = (grn_hash *)table;
1406       WITH_NORMALIZE(hash, key, key_size, {
1407         id = grn_hash_get(ctx, hash, key, key_size, NULL);
1408       });
1409     }
1410     break;
1411   }
1412   GRN_API_RETURN(id);
1413 }
1414 
1415 grn_obj *
grn_obj_default_set_value_hook(grn_ctx * ctx,int nargs,grn_obj ** args,grn_user_data * user_data)1416 grn_obj_default_set_value_hook(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1417 {
1418   grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
1419   if (!pctx) {
1420     ERR(GRN_INVALID_ARGUMENT, "default_set_value_hook failed");
1421   } else {
1422     grn_obj *flags = grn_ctx_pop(ctx);
1423     grn_obj *newvalue = grn_ctx_pop(ctx);
1424     grn_obj *oldvalue = grn_ctx_pop(ctx);
1425     grn_obj *id = grn_ctx_pop(ctx);
1426     grn_hook *h = pctx->currh;
1427     grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(h);
1428     grn_obj *target = grn_ctx_at(ctx, data->target);
1429     int section = data->section;
1430     if (flags) { /* todo */ }
1431     if (target) {
1432       switch (target->header.type) {
1433       case GRN_COLUMN_INDEX :
1434         grn_ii_column_update(ctx, (grn_ii *)target,
1435                              GRN_UINT32_VALUE(id),
1436                              section, oldvalue, newvalue, NULL);
1437       }
1438     }
1439   }
1440   return NULL;
1441 }
1442 
1443 grn_id
grn_table_add(grn_ctx * ctx,grn_obj * table,const void * key,unsigned int key_size,int * added)1444 grn_table_add(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size, int *added)
1445 {
1446   grn_id id = GRN_ID_NIL;
1447   GRN_API_ENTER;
1448   if (table) {
1449     int added_ = 0;
1450     switch (table->header.type) {
1451     case GRN_TABLE_PAT_KEY :
1452       {
1453         grn_pat *pat = (grn_pat *)table;
1454         WITH_NORMALIZE(pat, key, key_size, {
1455           if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
1456             if (grn_io_lock(ctx, pat->io, grn_lock_timeout)) {
1457               id = GRN_ID_NIL;
1458             } else {
1459               id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
1460               grn_io_unlock(pat->io);
1461             }
1462           } else {
1463             id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
1464           }
1465         });
1466         if (added) { *added = added_; }
1467       }
1468       break;
1469     case GRN_TABLE_DAT_KEY :
1470       {
1471         grn_dat *dat = (grn_dat *)table;
1472         WITH_NORMALIZE(dat, key, key_size, {
1473           if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
1474             if (grn_io_lock(ctx, dat->io, grn_lock_timeout)) {
1475               id = GRN_ID_NIL;
1476             } else {
1477               id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
1478               grn_io_unlock(dat->io);
1479             }
1480           } else {
1481             id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
1482           }
1483         });
1484         if (added) { *added = added_; }
1485       }
1486       break;
1487     case GRN_TABLE_HASH_KEY :
1488       {
1489         grn_hash *hash = (grn_hash *)table;
1490         WITH_NORMALIZE(hash, key, key_size, {
1491           if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
1492             if (grn_io_lock(ctx, hash->io, grn_lock_timeout)) {
1493               id = GRN_ID_NIL;
1494             } else {
1495               id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
1496               grn_io_unlock(hash->io);
1497             }
1498           } else {
1499             id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
1500           }
1501         });
1502         if (added) { *added = added_; }
1503       }
1504       break;
1505     case GRN_TABLE_NO_KEY :
1506       {
1507         grn_array *array = (grn_array *)table;
1508         if (array->io && !(array->io->flags & GRN_IO_TEMPORARY)) {
1509           if (grn_io_lock(ctx, array->io, grn_lock_timeout)) {
1510             id = GRN_ID_NIL;
1511           } else {
1512             id = grn_array_add(ctx, array, NULL);
1513             grn_io_unlock(array->io);
1514           }
1515         } else {
1516           id = grn_array_add(ctx, array, NULL);
1517         }
1518         added_ = id ? 1 : 0;
1519         if (added) { *added = added_; }
1520       }
1521       break;
1522     }
1523     if (added_) {
1524       grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT];
1525       if (hooks) {
1526         // todo : grn_proc_ctx_open()
1527         grn_obj id_, flags_, oldvalue_, value_;
1528         grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
1529         GRN_UINT32_INIT(&id_, 0);
1530         GRN_UINT32_INIT(&flags_, 0);
1531         GRN_TEXT_INIT(&oldvalue_, 0);
1532         GRN_TEXT_INIT(&value_, GRN_OBJ_DO_SHALLOW_COPY);
1533         GRN_TEXT_SET_REF(&value_, key, key_size);
1534         GRN_UINT32_SET(ctx, &id_, id);
1535         GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
1536         while (hooks) {
1537           grn_ctx_push(ctx, &id_);
1538           grn_ctx_push(ctx, &oldvalue_);
1539           grn_ctx_push(ctx, &value_);
1540           grn_ctx_push(ctx, &flags_);
1541           pctx.caller = NULL;
1542           pctx.currh = hooks;
1543           if (hooks->proc) {
1544             hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
1545           } else {
1546             grn_obj_default_set_value_hook(ctx, 1, &table, &pctx.user_data);
1547           }
1548           if (ctx->rc) { break; }
1549           hooks = hooks->next;
1550           pctx.offset++;
1551         }
1552       }
1553     }
1554   }
1555   GRN_API_RETURN(id);
1556 }
1557 
1558 grn_id
grn_table_get_by_key(grn_ctx * ctx,grn_obj * table,grn_obj * key)1559 grn_table_get_by_key(grn_ctx *ctx, grn_obj *table, grn_obj *key)
1560 {
1561   grn_id id = GRN_ID_NIL;
1562   if (table->header.domain == key->header.domain) {
1563     id = grn_table_get(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key));
1564   } else {
1565     grn_rc rc;
1566     grn_obj buf;
1567     GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
1568     if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
1569       grn_obj *domain = grn_ctx_at(ctx, table->header.domain);
1570       ERR_CAST(table, domain, key);
1571     } else {
1572       id = grn_table_get(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1573     }
1574     GRN_OBJ_FIN(ctx, &buf);
1575   }
1576   return id;
1577 }
1578 
1579 grn_id
grn_table_add_by_key(grn_ctx * ctx,grn_obj * table,grn_obj * key,int * added)1580 grn_table_add_by_key(grn_ctx *ctx, grn_obj *table, grn_obj *key, int *added)
1581 {
1582   grn_id id = GRN_ID_NIL;
1583   if (table->header.domain == key->header.domain) {
1584     id = grn_table_add(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key), added);
1585   } else {
1586     grn_rc rc;
1587     grn_obj buf;
1588     GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
1589     if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
1590       grn_obj *domain = grn_ctx_at(ctx, table->header.domain);
1591       ERR_CAST(table, domain, key);
1592     } else {
1593       id = grn_table_add(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), added);
1594     }
1595     GRN_OBJ_FIN(ctx, &buf);
1596   }
1597   return id;
1598 }
1599 
1600 grn_id
grn_table_get(grn_ctx * ctx,grn_obj * table,const void * key,unsigned int key_size)1601 grn_table_get(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
1602 {
1603   grn_id id = GRN_ID_NIL;
1604   GRN_API_ENTER;
1605   if (table) {
1606     if (table->header.type == GRN_DB) {
1607       grn_db *db = (grn_db *)table;
1608       table = db->keys;
1609     }
1610     switch (table->header.type) {
1611     case GRN_TABLE_PAT_KEY :
1612       WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1613         id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, NULL);
1614       });
1615       break;
1616     case GRN_TABLE_DAT_KEY :
1617       WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1618         id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, NULL);
1619       });
1620       break;
1621     case GRN_TABLE_HASH_KEY :
1622       WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1623         id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, NULL);
1624       });
1625       break;
1626     }
1627   }
1628   GRN_API_RETURN(id);
1629 }
1630 
1631 grn_id
grn_table_at(grn_ctx * ctx,grn_obj * table,grn_id id)1632 grn_table_at(grn_ctx *ctx, grn_obj *table, grn_id id)
1633 {
1634   GRN_API_ENTER;
1635   if (table) {
1636     switch (table->header.type) {
1637     case GRN_DB :
1638       {
1639         grn_db *db = (grn_db *)table;
1640         id = grn_table_at(ctx, db->keys, id);
1641       }
1642       break;
1643     case GRN_TABLE_PAT_KEY :
1644       id = grn_pat_at(ctx, (grn_pat *)table, id);
1645       break;
1646     case GRN_TABLE_DAT_KEY :
1647       id = grn_dat_at(ctx, (grn_dat *)table, id);
1648       break;
1649     case GRN_TABLE_HASH_KEY :
1650       id = grn_hash_at(ctx, (grn_hash *)table, id);
1651       break;
1652     case GRN_TABLE_NO_KEY :
1653       id = grn_array_at(ctx, (grn_array *)table, id);
1654       break;
1655     default :
1656       id = GRN_ID_NIL;
1657     }
1658   }
1659   GRN_API_RETURN(id);
1660 }
1661 
1662 inline static grn_id
grn_table_add_v_inline(grn_ctx * ctx,grn_obj * table,const void * key,int key_size,void ** value,int * added)1663 grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1664                        void **value, int *added)
1665 {
1666   grn_id id = GRN_ID_NIL;
1667   if (!key || !key_size) { return GRN_ID_NIL; }
1668   if (table) {
1669     switch (table->header.type) {
1670     case GRN_TABLE_PAT_KEY :
1671       WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1672         id = grn_pat_add(ctx, (grn_pat *)table, key, key_size, value, added);
1673       });
1674       break;
1675     case GRN_TABLE_DAT_KEY :
1676       WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1677         id = grn_dat_add(ctx, (grn_dat *)table, key, key_size, value, added);
1678       });
1679       break;
1680     case GRN_TABLE_HASH_KEY :
1681       WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1682         id = grn_hash_add(ctx, (grn_hash *)table, key, key_size, value, added);
1683       });
1684       break;
1685     case GRN_TABLE_NO_KEY :
1686       id = grn_array_add(ctx, (grn_array *)table, value);
1687       if (added) { *added = id ? 1 : 0; }
1688       break;
1689     }
1690   }
1691   return id;
1692 }
1693 
1694 grn_id
grn_table_add_v(grn_ctx * ctx,grn_obj * table,const void * key,int key_size,void ** value,int * added)1695 grn_table_add_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1696                 void **value, int *added) {
1697   grn_id id;
1698   GRN_API_ENTER;
1699   id = grn_table_add_v_inline(ctx, table, key, key_size, value, added);
1700   GRN_API_RETURN(id);
1701 }
1702 
1703 grn_id
grn_table_get_v(grn_ctx * ctx,grn_obj * table,const void * key,int key_size,void ** value)1704 grn_table_get_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1705                 void **value)
1706 {
1707   grn_id id = GRN_ID_NIL;
1708   GRN_API_ENTER;
1709   if (table) {
1710     switch (table->header.type) {
1711     case GRN_TABLE_PAT_KEY :
1712       WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1713         id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, value);
1714       });
1715       break;
1716     case GRN_TABLE_DAT_KEY :
1717       WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1718         id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, value);
1719       });
1720       break;
1721     case GRN_TABLE_HASH_KEY :
1722       WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1723         id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, value);
1724       });
1725       break;
1726     }
1727   }
1728   GRN_API_RETURN(id);
1729 }
1730 
1731 int
grn_table_get_key(grn_ctx * ctx,grn_obj * table,grn_id id,void * keybuf,int buf_size)1732 grn_table_get_key(grn_ctx *ctx, grn_obj *table, grn_id id, void *keybuf, int buf_size)
1733 {
1734   int r = 0;
1735   GRN_API_ENTER;
1736   if (table) {
1737     if (table->header.type == GRN_DB) {
1738       table = ((grn_db *)table)->keys;
1739     }
1740     switch (table->header.type) {
1741     case GRN_TABLE_HASH_KEY :
1742       r = grn_hash_get_key(ctx, (grn_hash *)table, id, keybuf, buf_size);
1743       break;
1744     case GRN_TABLE_PAT_KEY :
1745       r = grn_pat_get_key(ctx, (grn_pat *)table, id, keybuf, buf_size);
1746       break;
1747     case GRN_TABLE_DAT_KEY :
1748       r = grn_dat_get_key(ctx, (grn_dat *)table, id, keybuf, buf_size);
1749       break;
1750     case GRN_TABLE_NO_KEY :
1751       {
1752         grn_array *a = (grn_array *)table;
1753         if (a->obj.header.domain) {
1754           if (buf_size >= a->value_size) {
1755             r = grn_array_get_value(ctx, a, id, keybuf);
1756           } else {
1757             r = a->value_size;
1758           }
1759         }
1760       }
1761       break;
1762     }
1763   }
1764   GRN_API_RETURN(r);
1765 }
1766 
1767 int
grn_table_get_key2(grn_ctx * ctx,grn_obj * table,grn_id id,grn_obj * bulk)1768 grn_table_get_key2(grn_ctx *ctx, grn_obj *table, grn_id id, grn_obj *bulk)
1769 {
1770   int r = 0;
1771   GRN_API_ENTER;
1772   if (table) {
1773     if (table->header.type == GRN_DB) {
1774       table = ((grn_db *)table)->keys;
1775     }
1776     switch (table->header.type) {
1777     case GRN_TABLE_HASH_KEY :
1778       r = grn_hash_get_key2(ctx, (grn_hash *)table, id, bulk);
1779       break;
1780     case GRN_TABLE_PAT_KEY :
1781       r = grn_pat_get_key2(ctx, (grn_pat *)table, id, bulk);
1782       break;
1783     case GRN_TABLE_DAT_KEY :
1784       r = grn_dat_get_key2(ctx, (grn_dat *)table, id, bulk);
1785       break;
1786     case GRN_TABLE_NO_KEY :
1787       {
1788         grn_array *a = (grn_array *)table;
1789         if (a->obj.header.domain) {
1790           if (!grn_bulk_space(ctx, bulk, a->value_size)) {
1791             char *curr = GRN_BULK_CURR(bulk);
1792             r = grn_array_get_value(ctx, a, id, curr - a->value_size);
1793           }
1794         }
1795       }
1796       break;
1797     }
1798   }
1799   GRN_API_RETURN(r);
1800 }
1801 
1802 static grn_rc
grn_obj_clear_value(grn_ctx * ctx,grn_obj * obj,grn_id id)1803 grn_obj_clear_value(grn_ctx *ctx, grn_obj *obj, grn_id id)
1804 {
1805   grn_rc rc = GRN_SUCCESS;
1806   if (GRN_DB_OBJP(obj)) {
1807     grn_obj buf;
1808     grn_id range = DB_OBJ(obj)->range;
1809     GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
1810     switch (obj->header.type) {
1811     case GRN_COLUMN_VAR_SIZE :
1812     case GRN_COLUMN_FIX_SIZE :
1813       rc = grn_obj_set_value(ctx, obj, id, &buf, GRN_OBJ_SET);
1814       break;
1815     }
1816     GRN_OBJ_FIN(ctx, &buf);
1817   }
1818   return rc;
1819 }
1820 
1821 static void
call_delete_hook(grn_ctx * ctx,grn_obj * table,grn_id rid,const void * key,unsigned int key_size)1822 call_delete_hook(grn_ctx *ctx, grn_obj *table, grn_id rid, const void *key, unsigned int key_size)
1823 {
1824   if (rid) {
1825     grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_DELETE];
1826     if (hooks) {
1827       // todo : grn_proc_ctx_open()
1828       grn_obj id_, flags_, oldvalue_, value_;
1829       grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
1830       GRN_UINT32_INIT(&id_, 0);
1831       GRN_UINT32_INIT(&flags_, 0);
1832       GRN_TEXT_INIT(&oldvalue_, GRN_OBJ_DO_SHALLOW_COPY);
1833       GRN_TEXT_INIT(&value_, 0);
1834       GRN_TEXT_SET_REF(&oldvalue_, key, key_size);
1835       GRN_UINT32_SET(ctx, &id_, rid);
1836       GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
1837       while (hooks) {
1838         grn_ctx_push(ctx, &id_);
1839         grn_ctx_push(ctx, &oldvalue_);
1840         grn_ctx_push(ctx, &value_);
1841         grn_ctx_push(ctx, &flags_);
1842         pctx.caller = NULL;
1843         pctx.currh = hooks;
1844         if (hooks->proc) {
1845           hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
1846         } else {
1847           grn_obj_default_set_value_hook(ctx, 1, &table, &pctx.user_data);
1848         }
1849         if (ctx->rc) { break; }
1850         hooks = hooks->next;
1851         pctx.offset++;
1852       }
1853     }
1854   }
1855 }
1856 
1857 static void
clear_column_values(grn_ctx * ctx,grn_obj * table,grn_id rid)1858 clear_column_values(grn_ctx *ctx, grn_obj *table, grn_id rid)
1859 {
1860   if (rid) {
1861     grn_hash *cols;
1862     if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1863                                 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
1864       if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
1865         grn_id *key;
1866         GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
1867           grn_obj *col = grn_ctx_at(ctx, *key);
1868           if (col) { grn_obj_clear_value(ctx, col, rid); }
1869         });
1870       }
1871       grn_hash_close(ctx, cols);
1872     }
1873   }
1874 }
1875 
1876 static void
delete_reference_records_in_index(grn_ctx * ctx,grn_obj * table,grn_id id,grn_obj * index)1877 delete_reference_records_in_index(grn_ctx *ctx, grn_obj *table, grn_id id,
1878                                   grn_obj *index)
1879 {
1880   grn_ii *ii = (grn_ii *)index;
1881   grn_ii_cursor *ii_cursor = NULL;
1882   grn_posting *posting;
1883   grn_obj source_ids;
1884   unsigned int i, n_ids;
1885   grn_obj sources;
1886   grn_bool have_reference_source = GRN_FALSE;
1887 
1888   GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
1889   GRN_PTR_INIT(&sources, GRN_OBJ_VECTOR, 0);
1890 
1891   grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
1892   n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
1893   if (n_ids == 0) {
1894     goto exit;
1895   }
1896 
1897   for (i = 0; i < n_ids; i++) {
1898     grn_id source_id;
1899     grn_obj *source;
1900 
1901     source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
1902     source = grn_ctx_at(ctx, source_id);
1903     if (grn_obj_get_range(ctx, source) == index->header.domain) {
1904       GRN_PTR_PUT(ctx, &sources, source);
1905       have_reference_source = GRN_TRUE;
1906     } else {
1907       grn_obj_unlink(ctx, source);
1908       GRN_PTR_PUT(ctx, &sources, NULL);
1909     }
1910   }
1911 
1912   if (!have_reference_source) {
1913     goto exit;
1914   }
1915 
1916   ii_cursor = grn_ii_cursor_open(ctx, ii, id, GRN_ID_NIL, GRN_ID_MAX,
1917                                  ii->n_elements, 0);
1918   if (!ii_cursor) {
1919     goto exit;
1920   }
1921 
1922   while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
1923     grn_obj *source = GRN_PTR_VALUE_AT(&sources, posting->sid - 1);
1924     if (!source) {
1925       continue;
1926     }
1927     switch (source->header.type) {
1928     case GRN_COLUMN_VAR_SIZE :
1929       switch (source->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
1930       case GRN_OBJ_COLUMN_SCALAR :
1931         grn_obj_clear_value(ctx, source, posting->rid);
1932         break;
1933       case GRN_OBJ_COLUMN_VECTOR :
1934         {
1935           grn_obj value;
1936           grn_obj new_value;
1937           GRN_TEXT_INIT(&value, 0);
1938           grn_obj_get_value(ctx, source, posting->rid, &value);
1939           if (value.header.type == GRN_UVECTOR) {
1940             int i, n_ids;
1941             GRN_RECORD_INIT(&new_value, GRN_OBJ_VECTOR, value.header.domain);
1942             n_ids = GRN_BULK_VSIZE(&value) / sizeof(grn_id);
1943             for (i = 0; i < n_ids; i++) {
1944               grn_id reference_id = GRN_RECORD_VALUE_AT(&value, i);
1945               if (reference_id == id) {
1946                 continue;
1947               }
1948               GRN_RECORD_PUT(ctx, &new_value, reference_id);
1949             }
1950           } else {
1951             unsigned int i, n_elements;
1952             GRN_TEXT_INIT(&new_value, GRN_OBJ_VECTOR);
1953             n_elements = grn_vector_size(ctx, &value);
1954             for (i = 0; i < n_elements; i++) {
1955               const char *content;
1956               unsigned int content_length;
1957               unsigned int weight;
1958               grn_id domain;
1959               content_length =
1960                 grn_vector_get_element(ctx, &value, i,
1961                                        &content, &weight, &domain);
1962               if (grn_table_get(ctx, table, content, content_length) == id) {
1963                 continue;
1964               }
1965               grn_vector_add_element(ctx, &new_value, content, content_length,
1966                                      weight, domain);
1967             }
1968           }
1969           grn_obj_set_value(ctx, source, posting->rid, &new_value,
1970                             GRN_OBJ_SET);
1971           GRN_OBJ_FIN(ctx, &new_value);
1972           GRN_OBJ_FIN(ctx, &value);
1973         }
1974         break;
1975       }
1976       break;
1977     case GRN_COLUMN_FIX_SIZE :
1978       grn_obj_clear_value(ctx, source, posting->rid);
1979       break;
1980     }
1981   }
1982 
1983 exit:
1984   if (ii_cursor) {
1985     grn_ii_cursor_close(ctx, ii_cursor);
1986   }
1987   grn_obj_unlink(ctx, &source_ids);
1988   {
1989     int i, n_sources;
1990     n_sources = GRN_BULK_VSIZE(&sources) / sizeof(grn_obj *);
1991     for (i = 0; i < n_sources; i++) {
1992       grn_obj *source = GRN_PTR_VALUE_AT(&sources, i);
1993       grn_obj_unlink(ctx, source);
1994     }
1995     grn_obj_unlink(ctx, &sources);
1996   }
1997 }
1998 
1999 static grn_rc
delete_reference_records(grn_ctx * ctx,grn_obj * table,grn_id id)2000 delete_reference_records(grn_ctx *ctx, grn_obj *table, grn_id id)
2001 {
2002   grn_hash *cols;
2003   grn_id *key;
2004 
2005   cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
2006                          GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
2007   if (!cols) {
2008     return ctx->rc;
2009   }
2010 
2011   if (!grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
2012     grn_hash_close(ctx, cols);
2013     return ctx->rc;
2014   }
2015 
2016   GRN_HASH_EACH(ctx, cols, tid, &key, NULL, NULL, {
2017     grn_obj *col = grn_ctx_at(ctx, *key);
2018     if (!col) {
2019       continue;
2020     }
2021     if (col->header.type != GRN_COLUMN_INDEX) {
2022       continue;
2023     }
2024     delete_reference_records_in_index(ctx, table, id, col);
2025     if (ctx->rc != GRN_SUCCESS) {
2026       break;
2027     }
2028   });
2029 
2030   grn_hash_close(ctx, cols);
2031 
2032   return ctx->rc;
2033 }
2034 
2035 static grn_rc
grn_table_delete_prepare(grn_ctx * ctx,grn_obj * table,grn_id id,const void * key,unsigned int key_size)2036 grn_table_delete_prepare(grn_ctx *ctx, grn_obj *table,
2037                          grn_id id, const void *key, unsigned int key_size)
2038 {
2039   grn_rc rc;
2040 
2041   rc = delete_reference_records(ctx, table, id);
2042   if (rc != GRN_SUCCESS) {
2043     return rc;
2044   }
2045   call_delete_hook(ctx, table, id, key, key_size);
2046   clear_column_values(ctx, table, id);
2047 
2048   return rc;
2049 }
2050 
2051 grn_rc
grn_table_delete(grn_ctx * ctx,grn_obj * table,const void * key,unsigned int key_size)2052 grn_table_delete(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
2053 {
2054   grn_id rid = GRN_ID_NIL;
2055   grn_rc rc = GRN_INVALID_ARGUMENT;
2056   GRN_API_ENTER;
2057   if (table) {
2058     if (key && key_size) { rid = grn_table_get(ctx, table, key, key_size); }
2059     if (rid) {
2060       rc = grn_table_delete_prepare(ctx, table, rid, key, key_size);
2061       if (rc != GRN_SUCCESS) {
2062         goto exit;
2063       }
2064       switch (table->header.type) {
2065       case GRN_DB :
2066         /* todo : delete tables and columns from db */
2067         break;
2068       case GRN_TABLE_PAT_KEY :
2069         WITH_NORMALIZE((grn_pat *)table, key, key_size, {
2070           grn_pat *pat = (grn_pat *)table;
2071           if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
2072             if (!(rc = grn_io_lock(ctx, pat->io, grn_lock_timeout))) {
2073               rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
2074               grn_io_unlock(pat->io);
2075             }
2076           } else {
2077             rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
2078           }
2079         });
2080         break;
2081       case GRN_TABLE_DAT_KEY :
2082         WITH_NORMALIZE((grn_dat *)table, key, key_size, {
2083           grn_dat *dat = (grn_dat *)table;
2084           if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
2085             if (!(rc = grn_io_lock(ctx, dat->io, grn_lock_timeout))) {
2086               rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
2087               grn_io_unlock(dat->io);
2088             }
2089           } else {
2090             rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
2091           }
2092         });
2093         break;
2094       case GRN_TABLE_HASH_KEY :
2095         WITH_NORMALIZE((grn_hash *)table, key, key_size, {
2096           grn_hash *hash = (grn_hash *)table;
2097           if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
2098             if (!(rc = grn_io_lock(ctx, hash->io, grn_lock_timeout))) {
2099               rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
2100               grn_io_unlock(hash->io);
2101             }
2102           } else {
2103             rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
2104           }
2105         });
2106         break;
2107       }
2108       if (rc == GRN_SUCCESS) {
2109         grn_obj_touch(ctx, table, NULL);
2110       }
2111     }
2112   }
2113 exit :
2114   GRN_API_RETURN(rc);
2115 }
2116 
2117 grn_rc
_grn_table_delete_by_id(grn_ctx * ctx,grn_obj * table,grn_id id,grn_table_delete_optarg * optarg)2118 _grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
2119                        grn_table_delete_optarg *optarg)
2120 {
2121   grn_rc rc = GRN_INVALID_ARGUMENT;
2122   if (table) {
2123     if (id) {
2124       const void *key = NULL;
2125       unsigned int key_size = 0;
2126 
2127       if (table->header.type != GRN_TABLE_NO_KEY) {
2128         key = _grn_table_key(ctx, table, id, &key_size);
2129       }
2130       rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2131       if (rc != GRN_SUCCESS) {
2132         goto exit;
2133       }
2134       // todo : support optarg
2135       switch (table->header.type) {
2136       case GRN_TABLE_PAT_KEY :
2137         rc = grn_pat_delete_by_id(ctx, (grn_pat *)table, id, optarg);
2138         break;
2139       case GRN_TABLE_DAT_KEY :
2140         rc = grn_dat_delete_by_id(ctx, (grn_dat *)table, id, optarg);
2141         break;
2142       case GRN_TABLE_HASH_KEY :
2143         rc = grn_hash_delete_by_id(ctx, (grn_hash *)table, id, optarg);
2144         break;
2145       case GRN_TABLE_NO_KEY :
2146         rc = grn_array_delete_by_id(ctx, (grn_array *)table, id, optarg);
2147         break;
2148       }
2149     }
2150   }
2151 exit :
2152   return rc;
2153 }
2154 
2155 grn_rc
grn_table_delete_by_id(grn_ctx * ctx,grn_obj * table,grn_id id)2156 grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id)
2157 {
2158   grn_rc rc;
2159   grn_io *io;
2160   GRN_API_ENTER;
2161   if ((io = grn_obj_get_io(ctx, table)) && !(io->flags & GRN_IO_TEMPORARY)) {
2162     if (!(rc = grn_io_lock(ctx, io, grn_lock_timeout))) {
2163       rc = _grn_table_delete_by_id(ctx, table, id, NULL);
2164       grn_io_unlock(io);
2165     }
2166   } else {
2167     rc = _grn_table_delete_by_id(ctx, table, id, NULL);
2168   }
2169   if (rc == GRN_SUCCESS) {
2170     grn_obj_touch(ctx, table, NULL);
2171   }
2172   GRN_API_RETURN(rc);
2173 }
2174 
2175 grn_rc grn_ja_truncate(grn_ctx *ctx, grn_ja *ja);
2176 grn_rc grn_ra_truncate(grn_ctx *ctx, grn_ra *ra);
2177 
2178 grn_rc
grn_column_truncate(grn_ctx * ctx,grn_obj * column)2179 grn_column_truncate(grn_ctx *ctx, grn_obj *column)
2180 {
2181   grn_rc rc = GRN_INVALID_ARGUMENT;
2182   GRN_API_ENTER;
2183   if (column) {
2184     grn_hook *hooks;
2185     switch (column->header.type) {
2186     case GRN_COLUMN_INDEX :
2187       rc = grn_ii_truncate(ctx, (grn_ii *)column);
2188       break;
2189     case GRN_COLUMN_VAR_SIZE :
2190       for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
2191         grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2192         grn_obj *target = grn_ctx_at(ctx, data->target);
2193         if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2194         if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2195       }
2196       rc = grn_ja_truncate(ctx, (grn_ja *)column);
2197       break;
2198     case GRN_COLUMN_FIX_SIZE :
2199       for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
2200         grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2201         grn_obj *target = grn_ctx_at(ctx, data->target);
2202         if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2203         if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2204       }
2205       rc = grn_ra_truncate(ctx, (grn_ra *)column);
2206       break;
2207     }
2208     if (rc == GRN_SUCCESS) {
2209       grn_obj_touch(ctx, column, NULL);
2210     }
2211   }
2212 exit :
2213   GRN_API_RETURN(rc);
2214 }
2215 
2216 grn_rc
grn_table_truncate(grn_ctx * ctx,grn_obj * table)2217 grn_table_truncate(grn_ctx *ctx, grn_obj *table)
2218 {
2219   grn_rc rc = GRN_INVALID_ARGUMENT;
2220   GRN_API_ENTER;
2221   if (table) {
2222     grn_hook *hooks;
2223     grn_hash *cols;
2224     grn_obj *tokenizer;
2225     grn_obj *normalizer;
2226     grn_obj token_filters;
2227     if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
2228                                 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
2229       if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
2230         grn_id *key;
2231         GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
2232           grn_obj *col = grn_ctx_at(ctx, *key);
2233           if (col) { grn_column_truncate(ctx, col); }
2234         });
2235       }
2236       grn_hash_close(ctx, cols);
2237     }
2238     if (table->header.type != GRN_TABLE_NO_KEY) {
2239       grn_table_get_info(ctx, table, NULL, NULL, &tokenizer, &normalizer, NULL);
2240       GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, GRN_ID_NIL);
2241       grn_obj_get_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
2242     }
2243     switch (table->header.type) {
2244     case GRN_TABLE_PAT_KEY :
2245       for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
2246         grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2247         grn_obj *target = grn_ctx_at(ctx, data->target);
2248         if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2249         if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2250       }
2251       rc = grn_pat_truncate(ctx, (grn_pat *)table);
2252       break;
2253     case GRN_TABLE_DAT_KEY :
2254       for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
2255         grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2256         grn_obj *target = grn_ctx_at(ctx, data->target);
2257         if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2258         if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2259       }
2260       rc = grn_dat_truncate(ctx, (grn_dat *)table);
2261       break;
2262     case GRN_TABLE_HASH_KEY :
2263       for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
2264         grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2265         grn_obj *target = grn_ctx_at(ctx, data->target);
2266         if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2267         if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2268       }
2269       rc = grn_hash_truncate(ctx, (grn_hash *)table);
2270       break;
2271     case GRN_TABLE_NO_KEY :
2272       rc = grn_array_truncate(ctx, (grn_array *)table);
2273       break;
2274     }
2275     if (table->header.type != GRN_TABLE_NO_KEY) {
2276       grn_obj_set_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
2277       grn_obj_set_info(ctx, table, GRN_INFO_NORMALIZER, normalizer);
2278       grn_obj_set_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
2279       GRN_OBJ_FIN(ctx, &token_filters);
2280     }
2281     if (rc == GRN_SUCCESS) {
2282       grn_obj_touch(ctx, table, NULL);
2283     }
2284   }
2285 exit :
2286   GRN_API_RETURN(rc);
2287 }
2288 
2289 grn_rc
grn_table_get_info(grn_ctx * ctx,grn_obj * table,grn_table_flags * flags,grn_encoding * encoding,grn_obj ** tokenizer,grn_obj ** normalizer,grn_obj ** token_filters)2290 grn_table_get_info(grn_ctx *ctx, grn_obj *table, grn_table_flags *flags,
2291                    grn_encoding *encoding, grn_obj **tokenizer,
2292                    grn_obj **normalizer,
2293                    grn_obj **token_filters)
2294 {
2295   grn_rc rc = GRN_INVALID_ARGUMENT;
2296   GRN_API_ENTER;
2297   if (table) {
2298     switch (table->header.type) {
2299     case GRN_TABLE_PAT_KEY :
2300       if (flags) { *flags = ((grn_pat *)table)->header->flags; }
2301       if (encoding) { *encoding = ((grn_pat *)table)->encoding; }
2302       if (tokenizer) { *tokenizer = ((grn_pat *)table)->tokenizer; }
2303       if (normalizer) { *normalizer = ((grn_pat *)table)->normalizer; }
2304       if (token_filters) { *token_filters = &(((grn_pat *)table)->token_filters); }
2305       rc = GRN_SUCCESS;
2306       break;
2307     case GRN_TABLE_DAT_KEY :
2308       if (flags) { *flags = ((grn_dat *)table)->header->flags; }
2309       if (encoding) { *encoding = ((grn_dat *)table)->encoding; }
2310       if (tokenizer) { *tokenizer = ((grn_dat *)table)->tokenizer; }
2311       if (normalizer) { *normalizer = ((grn_dat *)table)->normalizer; }
2312       if (token_filters) { *token_filters = &(((grn_dat *)table)->token_filters); }
2313       rc = GRN_SUCCESS;
2314       break;
2315     case GRN_TABLE_HASH_KEY :
2316       if (flags) { *flags = ((grn_hash *)table)->header.common->flags; }
2317       if (encoding) { *encoding = ((grn_hash *)table)->encoding; }
2318       if (tokenizer) { *tokenizer = ((grn_hash *)table)->tokenizer; }
2319       if (normalizer) { *normalizer = ((grn_hash *)table)->normalizer; }
2320       if (token_filters) { *token_filters = &(((grn_hash *)table)->token_filters); }
2321       rc = GRN_SUCCESS;
2322       break;
2323     case GRN_TABLE_NO_KEY :
2324       if (flags) { *flags = grn_array_get_flags(ctx, ((grn_array *)table)); }
2325       if (encoding) { *encoding = GRN_ENC_NONE; }
2326       if (tokenizer) { *tokenizer = NULL; }
2327       if (normalizer) { *normalizer = NULL; }
2328       if (token_filters) { *token_filters = NULL; }
2329       rc = GRN_SUCCESS;
2330       break;
2331     }
2332   }
2333   GRN_API_RETURN(rc);
2334 }
2335 
2336 unsigned int
grn_table_size(grn_ctx * ctx,grn_obj * table)2337 grn_table_size(grn_ctx *ctx, grn_obj *table)
2338 {
2339   unsigned int n = 0;
2340   GRN_API_ENTER;
2341   if (table) {
2342     switch (table->header.type) {
2343     case GRN_DB :
2344       n = grn_table_size(ctx, ((grn_db *)table)->keys);
2345       break;
2346     case GRN_TABLE_PAT_KEY :
2347       n = grn_pat_size(ctx, (grn_pat *)table);
2348       break;
2349     case GRN_TABLE_DAT_KEY :
2350       n = grn_dat_size(ctx, (grn_dat *)table);
2351       break;
2352     case GRN_TABLE_HASH_KEY :
2353       n = grn_hash_size(ctx, (grn_hash *)table);
2354       break;
2355     case GRN_TABLE_NO_KEY :
2356       n = grn_array_size(ctx, (grn_array *)table);
2357       break;
2358     default :
2359       ERR(GRN_INVALID_ARGUMENT, "not supported");
2360       break;
2361     }
2362   } else {
2363     ERR(GRN_INVALID_ARGUMENT, "invalid table assigned");
2364   }
2365   GRN_API_RETURN(n);
2366 }
2367 
2368 inline static void
subrecs_push(byte * subrecs,int size,int n_subrecs,double score,void * body,int dir)2369 subrecs_push(byte *subrecs, int size, int n_subrecs, double score, void *body, int dir)
2370 {
2371   byte *v;
2372   double *c2;
2373   int n = n_subrecs - 1, n2;
2374   while (n) {
2375     n2 = (n - 1) >> 1;
2376     c2 = GRN_RSET_SUBRECS_NTH(subrecs,size,n2);
2377     if (GRN_RSET_SUBRECS_CMP(score, *c2, dir) >= 0) { break; }
2378     GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2379     n = n2;
2380   }
2381   v = subrecs + n * (GRN_RSET_SCORE_SIZE + size);
2382   *((double *)v) = score;
2383   grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
2384 }
2385 
2386 inline static void
subrecs_replace_min(byte * subrecs,int size,int n_subrecs,double score,void * body,int dir)2387 subrecs_replace_min(byte *subrecs, int size, int n_subrecs, double score, void *body, int dir)
2388 {
2389   byte *v;
2390   int n = 0, n1, n2;
2391   double *c1, *c2;
2392   for (;;) {
2393     n1 = n * 2 + 1;
2394     n2 = n1 + 1;
2395     c1 = n1 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n1) : NULL;
2396     c2 = n2 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n2) : NULL;
2397     if (c1 && GRN_RSET_SUBRECS_CMP(score, *c1, dir) > 0) {
2398       if (c2 &&
2399           GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0 &&
2400           GRN_RSET_SUBRECS_CMP(*c1, *c2, dir) > 0) {
2401         GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2402         n = n2;
2403       } else {
2404         GRN_RSET_SUBRECS_COPY(subrecs,size,n,c1);
2405         n = n1;
2406       }
2407     } else {
2408       if (c2 && GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) {
2409         GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2410         n = n2;
2411       } else {
2412         break;
2413       }
2414     }
2415   }
2416   v = subrecs + n * (GRN_RSET_SCORE_SIZE + size);
2417   grn_memcpy(v, &score, GRN_RSET_SCORE_SIZE);
2418   grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
2419 }
2420 
2421 inline static void
grn_table_add_subrec_inline(grn_obj * table,grn_rset_recinfo * ri,double score,grn_rset_posinfo * pi,int dir)2422 grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, double score,
2423                             grn_rset_posinfo *pi, int dir)
2424 {
2425   if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
2426     int limit = DB_OBJ(table)->max_n_subrecs;
2427     ri->score += score;
2428     ri->n_subrecs += 1;
2429     if (limit) {
2430       int subrec_size = DB_OBJ(table)->subrec_size;
2431       int n_subrecs = GRN_RSET_N_SUBRECS(ri);
2432       if (pi) {
2433         byte *body = (byte *)pi + DB_OBJ(table)->subrec_offset;
2434         if (limit < n_subrecs) {
2435           if (GRN_RSET_SUBRECS_CMP(score, *((double *)(ri->subrecs)), dir) > 0) {
2436             subrecs_replace_min((byte *)ri->subrecs, subrec_size, limit, score, body, dir);
2437           }
2438         } else {
2439           subrecs_push((byte *)ri->subrecs, subrec_size, n_subrecs, score, body, dir);
2440         }
2441       }
2442     }
2443   }
2444 }
2445 
2446 void
grn_table_add_subrec(grn_obj * table,grn_rset_recinfo * ri,double score,grn_rset_posinfo * pi,int dir)2447 grn_table_add_subrec(grn_obj *table, grn_rset_recinfo *ri, double score,
2448                      grn_rset_posinfo *pi, int dir)
2449 {
2450   grn_table_add_subrec_inline(table, ri, score, pi, dir);
2451 }
2452 
2453 grn_table_cursor *
grn_table_cursor_open(grn_ctx * ctx,grn_obj * table,const void * min,unsigned int min_size,const void * max,unsigned int max_size,int offset,int limit,int flags)2454 grn_table_cursor_open(grn_ctx *ctx, grn_obj *table,
2455                       const void *min, unsigned int min_size,
2456                       const void *max, unsigned int max_size,
2457                       int offset, int limit, int flags)
2458 {
2459   grn_rc rc;
2460   grn_table_cursor *tc = NULL;
2461   unsigned int table_size;
2462   if (!table) { return tc; }
2463   GRN_API_ENTER;
2464   table_size = grn_table_size(ctx, table);
2465   if (flags & GRN_CURSOR_PREFIX) {
2466     if (offset < 0) {
2467       ERR(GRN_TOO_SMALL_OFFSET,
2468           "can't use negative offset with GRN_CURSOR_PREFIX: %d", offset);
2469     } else if (offset != 0 && offset >= table_size) {
2470       ERR(GRN_TOO_LARGE_OFFSET,
2471           "offset is not less than table size: offset:%d, table_size:%d",
2472           offset, table_size);
2473     } else {
2474       if (limit < -1) {
2475         ERR(GRN_TOO_SMALL_LIMIT,
2476             "can't use smaller limit than -1 with GRN_CURSOR_PREFIX: %d",
2477             limit);
2478       } else if (limit == -1) {
2479         limit = table_size;
2480       }
2481     }
2482   } else {
2483     rc = grn_normalize_offset_and_limit(ctx, table_size, &offset, &limit);
2484     if (rc) {
2485       ERR(rc, "grn_normalize_offset_and_limit failed");
2486     }
2487   }
2488   if (!ctx->rc) {
2489     if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
2490     switch (table->header.type) {
2491     case GRN_TABLE_PAT_KEY :
2492       {
2493         grn_pat *pat = (grn_pat *)table;
2494         WITH_NORMALIZE(pat, min, min_size, {
2495           WITH_NORMALIZE(pat, max, max_size, {
2496             grn_pat_cursor *pat_cursor;
2497             pat_cursor = grn_pat_cursor_open(ctx, pat,
2498                                              min, min_size,
2499                                              max, max_size,
2500                                              offset, limit, flags);
2501             tc = (grn_table_cursor *)pat_cursor;
2502           });
2503         });
2504       }
2505       break;
2506     case GRN_TABLE_DAT_KEY :
2507       {
2508         grn_dat *dat = (grn_dat *)table;
2509         WITH_NORMALIZE(dat, min, min_size, {
2510           WITH_NORMALIZE(dat, max, max_size, {
2511             grn_dat_cursor *dat_cursor;
2512             dat_cursor = grn_dat_cursor_open(ctx, dat,
2513                                              min, min_size,
2514                                              max, max_size,
2515                                              offset, limit, flags);
2516             tc = (grn_table_cursor *)dat_cursor;
2517           });
2518         });
2519       }
2520       break;
2521     case GRN_TABLE_HASH_KEY :
2522       {
2523         grn_hash *hash = (grn_hash *)table;
2524         WITH_NORMALIZE(hash, min, min_size, {
2525           WITH_NORMALIZE(hash, max, max_size, {
2526             grn_hash_cursor *hash_cursor;
2527             hash_cursor = grn_hash_cursor_open(ctx, hash,
2528                                                min, min_size,
2529                                                max, max_size,
2530                                                offset, limit, flags);
2531             tc = (grn_table_cursor *)hash_cursor;
2532           });
2533         });
2534       }
2535       break;
2536     case GRN_TABLE_NO_KEY :
2537       tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
2538                                                      GRN_ID_NIL, GRN_ID_NIL,
2539                                                      offset, limit, flags);
2540       break;
2541     }
2542   }
2543   if (tc) {
2544     grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
2545     DB_OBJ(tc)->header.domain = GRN_ID_NIL;
2546     DB_OBJ(tc)->range = GRN_ID_NIL;
2547     grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(tc));
2548   }
2549   GRN_API_RETURN(tc);
2550 }
2551 
2552 grn_table_cursor *
grn_table_cursor_open_by_id(grn_ctx * ctx,grn_obj * table,grn_id min,grn_id max,int flags)2553 grn_table_cursor_open_by_id(grn_ctx *ctx, grn_obj *table,
2554                             grn_id min, grn_id max, int flags)
2555 {
2556   grn_table_cursor *tc = NULL;
2557   GRN_API_ENTER;
2558   if (table) {
2559     switch (table->header.type) {
2560     case GRN_TABLE_PAT_KEY :
2561       tc = (grn_table_cursor *)grn_pat_cursor_open(ctx, (grn_pat *)table,
2562                                                    NULL, 0, NULL, 0, 0, -1, flags);
2563       break;
2564     case GRN_TABLE_DAT_KEY :
2565       tc = (grn_table_cursor *)grn_dat_cursor_open(ctx, (grn_dat *)table,
2566                                                    NULL, 0, NULL, 0, 0, -1, flags);
2567       break;
2568     case GRN_TABLE_HASH_KEY :
2569       tc = (grn_table_cursor *)grn_hash_cursor_open(ctx, (grn_hash *)table,
2570                                                     NULL, 0, NULL, 0, 0, -1, flags);
2571       break;
2572     case GRN_TABLE_NO_KEY :
2573       tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
2574                                                      min, max, 0, -1, flags);
2575       break;
2576     }
2577   }
2578   GRN_API_RETURN(tc);
2579 }
2580 
2581 grn_rc
grn_table_cursor_close(grn_ctx * ctx,grn_table_cursor * tc)2582 grn_table_cursor_close(grn_ctx *ctx, grn_table_cursor *tc)
2583 {
2584   const char *tag = "[table][cursor][close]";
2585   grn_rc rc = GRN_SUCCESS;
2586   GRN_API_ENTER;
2587   if (!tc) {
2588     rc = GRN_INVALID_ARGUMENT;
2589     ERR(rc, "%s invalid cursor", tag);
2590   } else {
2591     {
2592       if (DB_OBJ(tc)->finalizer) {
2593         DB_OBJ(tc)->finalizer(ctx, 1, (grn_obj **)&tc, &DB_OBJ(tc)->user_data);
2594       }
2595       if (DB_OBJ(tc)->source) {
2596         GRN_FREE(DB_OBJ(tc)->source);
2597       }
2598       /*
2599       grn_hook_entry entry;
2600       for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
2601         grn_hook_free(ctx, DB_OBJ(tc)->hooks[entry]);
2602       }
2603       */
2604       grn_obj_delete_by_id(ctx, DB_OBJ(tc)->db, DB_OBJ(tc)->id, GRN_FALSE);
2605     }
2606     switch (tc->header.type) {
2607     case GRN_CURSOR_TABLE_PAT_KEY :
2608       grn_pat_cursor_close(ctx, (grn_pat_cursor *)tc);
2609       break;
2610     case GRN_CURSOR_TABLE_DAT_KEY :
2611       grn_dat_cursor_close(ctx, (grn_dat_cursor *)tc);
2612       break;
2613     case GRN_CURSOR_TABLE_HASH_KEY :
2614       grn_hash_cursor_close(ctx, (grn_hash_cursor *)tc);
2615       break;
2616     case GRN_CURSOR_TABLE_NO_KEY :
2617       grn_array_cursor_close(ctx, (grn_array_cursor *)tc);
2618       break;
2619     default :
2620       rc = GRN_INVALID_ARGUMENT;
2621       ERR(rc, "%s invalid type %d", tag, tc->header.type);
2622       break;
2623     }
2624   }
2625   GRN_API_RETURN(rc);
2626 }
2627 
2628 inline static grn_id
grn_table_cursor_next_inline(grn_ctx * ctx,grn_table_cursor * tc)2629 grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc)
2630 {
2631   const char *tag = "[table][cursor][next]";
2632   grn_id id = GRN_ID_NIL;
2633   if (!tc) {
2634     ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2635   } else {
2636     switch (tc->header.type) {
2637     case GRN_CURSOR_TABLE_PAT_KEY :
2638       id = grn_pat_cursor_next(ctx, (grn_pat_cursor *)tc);
2639       break;
2640     case GRN_CURSOR_TABLE_DAT_KEY :
2641       id = grn_dat_cursor_next(ctx, (grn_dat_cursor *)tc);
2642       break;
2643     case GRN_CURSOR_TABLE_HASH_KEY :
2644       id = grn_hash_cursor_next(ctx, (grn_hash_cursor *)tc);
2645       break;
2646     case GRN_CURSOR_TABLE_NO_KEY :
2647       id = grn_array_cursor_next(ctx, (grn_array_cursor *)tc);
2648       break;
2649     case GRN_CURSOR_COLUMN_INDEX :
2650       {
2651         grn_posting *ip = grn_index_cursor_next(ctx, (grn_obj *)tc, NULL);
2652         if (ip) { id = ip->rid; }
2653       }
2654       break;
2655     default :
2656       ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2657       break;
2658     }
2659   }
2660   return id;
2661 }
2662 
2663 grn_id
grn_table_cursor_next(grn_ctx * ctx,grn_table_cursor * tc)2664 grn_table_cursor_next(grn_ctx *ctx, grn_table_cursor *tc)
2665 {
2666   grn_id id;
2667   GRN_API_ENTER;
2668   id = grn_table_cursor_next_inline(ctx, tc);
2669   GRN_API_RETURN(id);
2670 }
2671 
2672 int
grn_table_cursor_get_key(grn_ctx * ctx,grn_table_cursor * tc,void ** key)2673 grn_table_cursor_get_key(grn_ctx *ctx, grn_table_cursor *tc, void **key)
2674 {
2675   const char *tag = "[table][cursor][get-key]";
2676   int len = 0;
2677   GRN_API_ENTER;
2678   if (!tc) {
2679     ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2680   } else {
2681     switch (tc->header.type) {
2682     case GRN_CURSOR_TABLE_PAT_KEY :
2683       len = grn_pat_cursor_get_key(ctx, (grn_pat_cursor *)tc, key);
2684       break;
2685     case GRN_CURSOR_TABLE_DAT_KEY :
2686       len = grn_dat_cursor_get_key(ctx, (grn_dat_cursor *)tc, (const void **)key);
2687       break;
2688     case GRN_CURSOR_TABLE_HASH_KEY :
2689       len = grn_hash_cursor_get_key(ctx, (grn_hash_cursor *)tc, key);
2690       break;
2691     default :
2692       ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2693       break;
2694     }
2695   }
2696   GRN_API_RETURN(len);
2697 }
2698 
2699 inline static int
grn_table_cursor_get_value_inline(grn_ctx * ctx,grn_table_cursor * tc,void ** value)2700 grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value)
2701 {
2702   const char *tag = "[table][cursor][get-value]";
2703   int len = 0;
2704   if (!tc) {
2705     ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2706   } else {
2707     switch (tc->header.type) {
2708     case GRN_CURSOR_TABLE_PAT_KEY :
2709       len = grn_pat_cursor_get_value(ctx, (grn_pat_cursor *)tc, value);
2710       break;
2711     case GRN_CURSOR_TABLE_DAT_KEY :
2712       *value = NULL;
2713       len = 0;
2714       break;
2715     case GRN_CURSOR_TABLE_HASH_KEY :
2716       len = grn_hash_cursor_get_value(ctx, (grn_hash_cursor *)tc, value);
2717       break;
2718     case GRN_CURSOR_TABLE_NO_KEY :
2719       len = grn_array_cursor_get_value(ctx, (grn_array_cursor *)tc, value);
2720       break;
2721     default :
2722       ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2723       break;
2724     }
2725   }
2726   return len;
2727 }
2728 
2729 int
grn_table_cursor_get_value(grn_ctx * ctx,grn_table_cursor * tc,void ** value)2730 grn_table_cursor_get_value(grn_ctx *ctx, grn_table_cursor *tc, void **value)
2731 {
2732   int len;
2733   GRN_API_ENTER;
2734   len = grn_table_cursor_get_value_inline(ctx, tc, value);
2735   GRN_API_RETURN(len);
2736 }
2737 
2738 grn_rc
grn_table_cursor_set_value(grn_ctx * ctx,grn_table_cursor * tc,const void * value,int flags)2739 grn_table_cursor_set_value(grn_ctx *ctx, grn_table_cursor *tc,
2740                            const void *value, int flags)
2741 {
2742   const char *tag = "[table][cursor][set-value]";
2743   grn_rc rc = GRN_INVALID_ARGUMENT;
2744   GRN_API_ENTER;
2745   if (!tc) {
2746     ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2747   } else {
2748     switch (tc->header.type) {
2749     case GRN_CURSOR_TABLE_PAT_KEY :
2750       rc = grn_pat_cursor_set_value(ctx, (grn_pat_cursor *)tc, value, flags);
2751       break;
2752     case GRN_CURSOR_TABLE_DAT_KEY :
2753       rc = GRN_OPERATION_NOT_SUPPORTED;
2754       break;
2755     case GRN_CURSOR_TABLE_HASH_KEY :
2756       rc = grn_hash_cursor_set_value(ctx, (grn_hash_cursor *)tc, value, flags);
2757       break;
2758     case GRN_CURSOR_TABLE_NO_KEY :
2759       rc = grn_array_cursor_set_value(ctx, (grn_array_cursor *)tc, value, flags);
2760       break;
2761     default :
2762       ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2763       break;
2764     }
2765   }
2766   GRN_API_RETURN(rc);
2767 }
2768 
2769 grn_rc
grn_table_cursor_delete(grn_ctx * ctx,grn_table_cursor * tc)2770 grn_table_cursor_delete(grn_ctx *ctx, grn_table_cursor *tc)
2771 {
2772   const char *tag = "[table][cursor][delete]";
2773   grn_rc rc = GRN_INVALID_ARGUMENT;
2774   GRN_API_ENTER;
2775   if (!tc) {
2776     ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2777   } else {
2778     grn_id id;
2779     grn_obj *table;
2780     const void *key = NULL;
2781     unsigned int key_size = 0;
2782     switch (tc->header.type) {
2783     case GRN_CURSOR_TABLE_PAT_KEY :
2784       {
2785         grn_pat_cursor *pc = (grn_pat_cursor *)tc;
2786         id = pc->curr_rec;
2787         table = (grn_obj *)(pc->pat);
2788         key = _grn_pat_key(ctx, pc->pat, id, &key_size);
2789         rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2790         if (rc != GRN_SUCCESS) {
2791           goto exit;
2792         }
2793         rc = grn_pat_cursor_delete(ctx, pc, NULL);
2794       }
2795       break;
2796     case GRN_CURSOR_TABLE_DAT_KEY :
2797       rc = GRN_OPERATION_NOT_SUPPORTED;
2798       break;
2799     case GRN_CURSOR_TABLE_HASH_KEY :
2800       {
2801         grn_hash_cursor *hc = (grn_hash_cursor *)tc;
2802         id = hc->curr_rec;
2803         table = (grn_obj *)(hc->hash);
2804         key = _grn_hash_key(ctx, hc->hash, id, &key_size);
2805         rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2806         if (rc != GRN_SUCCESS) {
2807           goto exit;
2808         }
2809         rc = grn_hash_cursor_delete(ctx, hc, NULL);
2810       }
2811       break;
2812     case GRN_CURSOR_TABLE_NO_KEY :
2813       {
2814         grn_array_cursor *ac = (grn_array_cursor *)tc;
2815         id = ac->curr_rec;
2816         table = (grn_obj *)(ac->array);
2817         rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2818         if (rc != GRN_SUCCESS) {
2819           goto exit;
2820         }
2821         rc = grn_array_cursor_delete(ctx, ac, NULL);
2822       }
2823       break;
2824     default :
2825       ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2826       break;
2827     }
2828   }
2829 exit :
2830   GRN_API_RETURN(rc);
2831 }
2832 
2833 grn_obj *
grn_table_cursor_table(grn_ctx * ctx,grn_table_cursor * tc)2834 grn_table_cursor_table(grn_ctx *ctx, grn_table_cursor *tc)
2835 {
2836   const char *tag = "[table][cursor][table]";
2837   grn_obj *obj = NULL;
2838   GRN_API_ENTER;
2839   if (!tc) {
2840     ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2841   } else {
2842     switch (tc->header.type) {
2843     case GRN_CURSOR_TABLE_PAT_KEY :
2844       obj = (grn_obj *)(((grn_pat_cursor *)tc)->pat);
2845       break;
2846     case GRN_CURSOR_TABLE_DAT_KEY :
2847       obj = (grn_obj *)(((grn_dat_cursor *)tc)->dat);
2848       break;
2849     case GRN_CURSOR_TABLE_HASH_KEY :
2850       obj = (grn_obj *)(((grn_hash_cursor *)tc)->hash);
2851       break;
2852     case GRN_CURSOR_TABLE_NO_KEY :
2853       obj = (grn_obj *)(((grn_array_cursor *)tc)->array);
2854       break;
2855     default :
2856       ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2857       break;
2858     }
2859   }
2860   GRN_API_RETURN(obj);
2861 }
2862 
2863 typedef struct {
2864   grn_db_obj obj;
2865   grn_obj *index;
2866   grn_table_cursor *tc;
2867   grn_ii_cursor *iic;
2868   grn_id tid;
2869   grn_id rid_min;
2870   grn_id rid_max;
2871   int flags;
2872 } grn_index_cursor;
2873 
2874 grn_obj *
grn_index_cursor_open(grn_ctx * ctx,grn_table_cursor * tc,grn_obj * index,grn_id rid_min,grn_id rid_max,int flags)2875 grn_index_cursor_open(grn_ctx *ctx, grn_table_cursor *tc,
2876                       grn_obj *index, grn_id rid_min, grn_id rid_max, int flags)
2877 {
2878   grn_index_cursor *ic = NULL;
2879   GRN_API_ENTER;
2880   if (tc && (ic = GRN_MALLOCN(grn_index_cursor, 1))) {
2881     ic->tc = tc;
2882     ic->index = index;
2883     ic->iic = NULL;
2884     ic->tid = GRN_ID_NIL;
2885     ic->rid_min = rid_min;
2886     ic->rid_max = rid_max;
2887     ic->flags = flags;
2888     GRN_DB_OBJ_SET_TYPE(ic, GRN_CURSOR_COLUMN_INDEX);
2889     {
2890       grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
2891       DB_OBJ(ic)->header.domain = GRN_ID_NIL;
2892       DB_OBJ(ic)->range = GRN_ID_NIL;
2893       grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(ic));
2894     }
2895   }
2896   GRN_API_RETURN((grn_obj *)ic);
2897 }
2898 
2899 grn_posting *
grn_index_cursor_next(grn_ctx * ctx,grn_obj * c,grn_id * tid)2900 grn_index_cursor_next(grn_ctx *ctx, grn_obj *c, grn_id *tid)
2901 {
2902   grn_posting *ip = NULL;
2903   grn_index_cursor *ic = (grn_index_cursor *)c;
2904   GRN_API_ENTER;
2905   if (ic->iic) {
2906     if (ic->flags & GRN_OBJ_WITH_POSITION) {
2907       ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2908       while (!ip && grn_ii_cursor_next(ctx, ic->iic)) {
2909         ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2910         break;
2911       }
2912     } else {
2913       ip = grn_ii_cursor_next(ctx, ic->iic);
2914     }
2915   }
2916   if (!ip) {
2917     while ((ic->tid = grn_table_cursor_next_inline(ctx, ic->tc))) {
2918       grn_ii *ii = (grn_ii *)ic->index;
2919       if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
2920       if ((ic->iic = grn_ii_cursor_open(ctx, ii, ic->tid,
2921                                         ic->rid_min, ic->rid_max,
2922                                         ii->n_elements, ic->flags))) {
2923         ip = grn_ii_cursor_next(ctx, ic->iic);
2924         if (ip && ic->flags & GRN_OBJ_WITH_POSITION) {
2925           ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2926         }
2927         if (ip) {
2928           break;
2929         }
2930       }
2931     }
2932   }
2933   if (tid) { *tid = ic->tid; }
2934   GRN_API_RETURN((grn_posting *)ip);
2935 }
2936 
2937 grn_rc
grn_table_search(grn_ctx * ctx,grn_obj * table,const void * key,uint32_t key_size,grn_operator mode,grn_obj * res,grn_operator op)2938 grn_table_search(grn_ctx *ctx, grn_obj *table, const void *key, uint32_t key_size,
2939                  grn_operator mode, grn_obj *res, grn_operator op)
2940 {
2941   grn_rc rc = GRN_SUCCESS;
2942   GRN_API_ENTER;
2943   switch (table->header.type) {
2944   case GRN_TABLE_PAT_KEY :
2945     {
2946       grn_pat *pat = (grn_pat *)table;
2947       WITH_NORMALIZE(pat, key, key_size, {
2948         switch (mode) {
2949         case GRN_OP_EXACT :
2950           {
2951             grn_id id = grn_pat_get(ctx, pat, key, key_size, NULL);
2952             if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2953           }
2954           // todo : support op;
2955           break;
2956         case GRN_OP_LCP :
2957           {
2958             grn_id id = grn_pat_lcp_search(ctx, pat, key, key_size);
2959             if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2960           }
2961           // todo : support op;
2962           break;
2963         case GRN_OP_SUFFIX :
2964           rc = grn_pat_suffix_search(ctx, pat, key, key_size, (grn_hash *)res);
2965           // todo : support op;
2966           break;
2967         case GRN_OP_PREFIX :
2968           rc = grn_pat_prefix_search(ctx, pat, key, key_size, (grn_hash *)res);
2969           // todo : support op;
2970           break;
2971         case GRN_OP_TERM_EXTRACT :
2972           {
2973             int len;
2974             grn_id tid;
2975             const char *sp = key;
2976             const char *se = sp + key_size;
2977             for (; sp < se; sp += len) {
2978               if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
2979                 grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
2980                 /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
2981               }
2982               if (!(len = grn_charlen(ctx, sp, se))) { break; }
2983             }
2984           }
2985           // todo : support op;
2986           break;
2987         default :
2988           rc = GRN_INVALID_ARGUMENT;
2989           ERR(rc, "invalid mode %d", mode);
2990         }
2991       });
2992     }
2993     break;
2994   case GRN_TABLE_DAT_KEY :
2995     {
2996       grn_dat *dat = (grn_dat *)table;
2997       WITH_NORMALIZE(dat, key, key_size, {
2998         switch (mode) {
2999         case GRN_OP_EXACT :
3000           {
3001             grn_id id = grn_dat_get(ctx, dat, key, key_size, NULL);
3002             if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
3003           }
3004           break;
3005         case GRN_OP_PREFIX :
3006           {
3007             grn_dat_cursor *dc = grn_dat_cursor_open(ctx, dat, key, key_size, NULL, 0,
3008                                                      0, -1, GRN_CURSOR_PREFIX);
3009             if (dc) {
3010               grn_id id;
3011               while ((id = grn_dat_cursor_next(ctx, dc))) {
3012                 grn_table_add(ctx, res, &id, sizeof(grn_id), NULL);
3013               }
3014               grn_dat_cursor_close(ctx, dc);
3015             }
3016           }
3017           break;
3018         case GRN_OP_LCP :
3019           {
3020             grn_id id = grn_dat_lcp_search(ctx, dat, key, key_size);
3021             if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
3022           }
3023           break;
3024         case GRN_OP_TERM_EXTRACT :
3025           {
3026             int len;
3027             grn_id tid;
3028             const char *sp = key;
3029             const char *se = sp + key_size;
3030             for (; sp < se; sp += len) {
3031               if ((tid = grn_dat_lcp_search(ctx, dat, sp, se - sp))) {
3032                 grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
3033                 /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
3034               }
3035               if (!(len = grn_charlen(ctx, sp, se))) { break; }
3036             }
3037           }
3038           // todo : support op;
3039           break;
3040         default :
3041           rc = GRN_INVALID_ARGUMENT;
3042           ERR(rc, "invalid mode %d", mode);
3043         }
3044       });
3045     }
3046     break;
3047   case GRN_TABLE_HASH_KEY :
3048     {
3049       grn_hash *hash = (grn_hash *)table;
3050       grn_id id = GRN_ID_NIL;
3051       WITH_NORMALIZE(hash, key, key_size, {
3052         id = grn_hash_get(ctx, hash, key, key_size, NULL);
3053       });
3054       if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
3055     }
3056     break;
3057   }
3058   GRN_API_RETURN(rc);
3059 }
3060 
3061 grn_rc
grn_table_fuzzy_search(grn_ctx * ctx,grn_obj * table,const void * key,uint32_t key_size,grn_fuzzy_search_optarg * args,grn_obj * res,grn_operator op)3062 grn_table_fuzzy_search(grn_ctx *ctx, grn_obj *table, const void *key, uint32_t key_size,
3063                        grn_fuzzy_search_optarg *args, grn_obj *res, grn_operator op)
3064 {
3065   grn_rc rc = GRN_SUCCESS;
3066   GRN_API_ENTER;
3067   switch (table->header.type) {
3068   case GRN_TABLE_PAT_KEY :
3069     {
3070       grn_pat *pat = (grn_pat *)table;
3071       if (!grn_table_size(ctx, res) && op == GRN_OP_OR) {
3072         WITH_NORMALIZE(pat, key, key_size, {
3073           rc = grn_pat_fuzzy_search(ctx, pat, key, key_size,
3074                                     args, (grn_hash *)res);
3075         });
3076       } else {
3077         grn_obj *hash;
3078         hash = grn_table_create(ctx, NULL, 0, NULL,
3079                                 GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3080                                 table, NULL);
3081         WITH_NORMALIZE(pat, key, key_size, {
3082           rc = grn_pat_fuzzy_search(ctx, pat, key, key_size,
3083                                     args, (grn_hash *)hash);
3084         });
3085         if (rc == GRN_SUCCESS) {
3086           rc = grn_table_setoperation(ctx, res, hash, res, op);
3087         }
3088         grn_obj_unlink(ctx, hash);
3089       }
3090     }
3091     break;
3092   default :
3093     rc = GRN_OPERATION_NOT_SUPPORTED;
3094     break;
3095   }
3096   GRN_API_RETURN(rc);
3097 }
3098 
3099 grn_id
grn_table_next(grn_ctx * ctx,grn_obj * table,grn_id id)3100 grn_table_next(grn_ctx *ctx, grn_obj *table, grn_id id)
3101 {
3102   grn_id r = GRN_ID_NIL;
3103   GRN_API_ENTER;
3104   if (table) {
3105     switch (table->header.type) {
3106     case GRN_TABLE_PAT_KEY :
3107       r = grn_pat_next(ctx, (grn_pat *)table, id);
3108       break;
3109     case GRN_TABLE_DAT_KEY :
3110       r = grn_dat_next(ctx, (grn_dat *)table, id);
3111       break;
3112     case GRN_TABLE_HASH_KEY :
3113       r = grn_hash_next(ctx, (grn_hash *)table, id);
3114       break;
3115     case GRN_TABLE_NO_KEY :
3116       r = grn_array_next(ctx, (grn_array *)table, id);
3117       break;
3118     }
3119   }
3120   GRN_API_RETURN(r);
3121 }
3122 
3123 static grn_rc
grn_accessor_resolve_one_index_column(grn_ctx * ctx,grn_accessor * accessor,grn_obj * current_res,grn_obj ** next_res)3124 grn_accessor_resolve_one_index_column(grn_ctx *ctx, grn_accessor *accessor,
3125                                       grn_obj *current_res, grn_obj **next_res)
3126 {
3127   grn_rc rc = GRN_SUCCESS;
3128   grn_obj *column = NULL;
3129   grn_id next_res_domain_id = GRN_ID_NIL;
3130 
3131   {
3132     grn_obj *index;
3133     grn_obj source_ids;
3134     unsigned int i, n_ids;
3135 
3136     index = accessor->obj;
3137     next_res_domain_id = index->header.domain;
3138 
3139     GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
3140     grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
3141     n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
3142     for (i = 0; i < n_ids; i++) {
3143       grn_id source_id;
3144       grn_obj *source;
3145 
3146       source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
3147       source = grn_ctx_at(ctx, source_id);
3148       if (DB_OBJ(source)->range == next_res_domain_id) {
3149         column = source;
3150         break;
3151       }
3152       grn_obj_unlink(ctx, source);
3153     }
3154 
3155     if (!column) {
3156       return GRN_INVALID_ARGUMENT;
3157     }
3158   }
3159 
3160   {
3161     grn_rc rc;
3162     grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
3163     *next_res = grn_table_create(ctx, NULL, 0, NULL,
3164                                  GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3165                                  next_res_domain, NULL);
3166     rc = ctx->rc;
3167     grn_obj_unlink(ctx, next_res_domain);
3168     if (!*next_res) {
3169       return rc;
3170     }
3171   }
3172 
3173   {
3174     grn_obj_flags column_value_flags = 0;
3175     grn_obj column_value;
3176     grn_posting add_posting;
3177     grn_id *tid;
3178     grn_rset_recinfo *recinfo;
3179 
3180     if (column->header.type == GRN_COLUMN_VAR_SIZE) {
3181       column_value_flags |= GRN_OBJ_VECTOR;
3182     }
3183     GRN_VALUE_FIX_SIZE_INIT(&column_value,
3184                             column_value_flags,
3185                             next_res_domain_id);
3186 
3187     add_posting.sid = 0;
3188     add_posting.pos = 0;
3189     add_posting.weight = 0;
3190 
3191     GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &tid, NULL, &recinfo, {
3192       int i;
3193       int n_elements;
3194 
3195       add_posting.weight = recinfo->score - 1;
3196 
3197       GRN_BULK_REWIND(&column_value);
3198       grn_obj_get_value(ctx, column, *tid, &column_value);
3199 
3200       n_elements = GRN_BULK_VSIZE(&column_value) / sizeof(grn_id);
3201       for (i = 0; i < n_elements; i++) {
3202         add_posting.rid = GRN_RECORD_VALUE_AT(&column_value, i);
3203         rc = grn_ii_posting_add(ctx,
3204                                 &add_posting,
3205                                 (grn_hash *)*next_res,
3206                                 GRN_OP_OR);
3207         if (rc != GRN_SUCCESS) {
3208           break;
3209         }
3210       }
3211       if (rc != GRN_SUCCESS) {
3212         break;
3213       }
3214     });
3215 
3216     GRN_OBJ_FIN(ctx, &column_value);
3217   }
3218 
3219   if (rc != GRN_SUCCESS) {
3220     grn_obj_unlink(ctx, *next_res);
3221   }
3222 
3223   return rc;
3224 }
3225 
3226 static grn_rc
grn_accessor_resolve_one_table(grn_ctx * ctx,grn_accessor * accessor,grn_obj * current_res,grn_obj ** next_res)3227 grn_accessor_resolve_one_table(grn_ctx *ctx, grn_accessor *accessor,
3228                                grn_obj *current_res, grn_obj **next_res)
3229 {
3230   grn_rc rc = GRN_SUCCESS;
3231   grn_obj *table;
3232 
3233   table = accessor->obj;
3234   *next_res = grn_table_create(ctx, NULL, 0, NULL,
3235                                GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3236                                table, NULL);
3237   if (!*next_res) {
3238     return ctx->rc;
3239   }
3240 
3241   grn_report_table(ctx,
3242                    "[accessor][resolve]",
3243                    "",
3244                    table);
3245 
3246   {
3247     grn_posting posting;
3248 
3249     memset(&posting, 0, sizeof(posting));
3250     GRN_HASH_EACH_BEGIN(ctx, (grn_hash *)current_res, cursor, id) {
3251       void *key;
3252       void *value;
3253       grn_id *record_id;
3254       grn_rset_recinfo *recinfo;
3255       grn_id next_record_id;
3256 
3257       grn_hash_cursor_get_key_value(ctx, cursor, &key, NULL, &value);
3258       record_id = key;
3259       recinfo = value;
3260       next_record_id = grn_table_get(ctx,
3261                                      table,
3262                                      record_id,
3263                                      sizeof(grn_id));
3264       if (next_record_id == GRN_ID_NIL) {
3265         continue;
3266       }
3267 
3268       posting.rid = next_record_id;
3269       posting.weight = recinfo->score;
3270       rc = grn_ii_posting_add(ctx,
3271                               &posting,
3272                               (grn_hash *)*next_res,
3273                               GRN_OP_OR);
3274       if (rc != GRN_SUCCESS) {
3275         break;
3276       }
3277     } GRN_HASH_EACH_END(ctx, cursor);
3278   }
3279 
3280   if (rc != GRN_SUCCESS) {
3281     grn_obj_unlink(ctx, *next_res);
3282   }
3283 
3284   return rc;
3285 }
3286 
3287 static grn_rc
grn_accessor_resolve_one_data_column(grn_ctx * ctx,grn_accessor * accessor,grn_obj * current_res,grn_obj ** next_res)3288 grn_accessor_resolve_one_data_column(grn_ctx *ctx, grn_accessor *accessor,
3289                                      grn_obj *current_res, grn_obj **next_res)
3290 {
3291   grn_rc rc = GRN_SUCCESS;
3292   grn_index_datum index_datum;
3293   unsigned int n_index_data;
3294   grn_id next_res_domain_id = GRN_ID_NIL;
3295 
3296   n_index_data = grn_column_get_all_index_data(ctx,
3297                                                accessor->obj,
3298                                                &index_datum,
3299                                                1);
3300   if (n_index_data == 0) {
3301     return GRN_INVALID_ARGUMENT;
3302   }
3303 
3304   {
3305     grn_obj *lexicon;
3306     lexicon = grn_ctx_at(ctx, index_datum.index->header.domain);
3307     if (grn_obj_id(ctx, lexicon) != current_res->header.domain) {
3308       char index_name[GRN_TABLE_MAX_KEY_SIZE];
3309       int index_name_size;
3310       grn_obj *expected;
3311       char expected_name[GRN_TABLE_MAX_KEY_SIZE];
3312       int expected_name_size;
3313 
3314       index_name_size = grn_obj_name(ctx,
3315                                      index_datum.index,
3316                                      index_name,
3317                                      GRN_TABLE_MAX_KEY_SIZE);
3318       expected = grn_ctx_at(ctx, current_res->header.domain);
3319       expected_name_size = grn_obj_name(ctx,
3320                                         expected,
3321                                         expected_name,
3322                                         GRN_TABLE_MAX_KEY_SIZE);
3323       ERR(GRN_INVALID_ARGUMENT,
3324           "[accessor][resolve][data-column] lexicon mismatch index: "
3325           "<%.*s> "
3326           "expected:<%.*s>",
3327           index_name_size,
3328           index_name,
3329           expected_name_size,
3330           expected_name);
3331       return ctx->rc;
3332     }
3333   }
3334 
3335   next_res_domain_id = DB_OBJ(index_datum.index)->range;
3336 
3337   grn_report_index(ctx,
3338                    "[accessor][resolve][data-column]",
3339                    "",
3340                    index_datum.index);
3341   {
3342     grn_rc rc;
3343     grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
3344     *next_res = grn_table_create(ctx, NULL, 0, NULL,
3345                                  GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3346                                  next_res_domain, NULL);
3347     rc = ctx->rc;
3348     grn_obj_unlink(ctx, next_res_domain);
3349     if (!*next_res) {
3350       return rc;
3351     }
3352   }
3353 
3354   {
3355     grn_id *tid;
3356     grn_rset_recinfo *recinfo;
3357 
3358     GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &tid, NULL, &recinfo, {
3359       grn_ii *ii = (grn_ii *)(index_datum.index);
3360       grn_ii_cursor *ii_cursor;
3361       grn_posting *posting;
3362 
3363       ii_cursor = grn_ii_cursor_open(ctx, ii, *tid,
3364                                      GRN_ID_NIL, GRN_ID_MAX,
3365                                      ii->n_elements,
3366                                      0);
3367       if (!ii_cursor) {
3368         continue;
3369       }
3370 
3371       while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
3372         grn_posting add_posting;
3373 
3374         if (index_datum.section > 0 && posting->sid != index_datum.section) {
3375           continue;
3376         }
3377 
3378         add_posting = *posting;
3379         add_posting.weight += recinfo->score - 1;
3380         rc = grn_ii_posting_add(ctx,
3381                                 &add_posting,
3382                                 (grn_hash *)*next_res,
3383                                 GRN_OP_OR);
3384         if (rc != GRN_SUCCESS) {
3385           break;
3386         }
3387       }
3388       grn_ii_cursor_close(ctx, ii_cursor);
3389 
3390       if (rc != GRN_SUCCESS) {
3391         break;
3392       }
3393     });
3394   }
3395 
3396   if (rc != GRN_SUCCESS) {
3397     grn_obj_unlink(ctx, *next_res);
3398   }
3399 
3400   return rc;
3401 }
3402 
3403 grn_rc
grn_accessor_resolve(grn_ctx * ctx,grn_obj * accessor,int deep,grn_obj * base_res,grn_obj * res,grn_operator op)3404 grn_accessor_resolve(grn_ctx *ctx, grn_obj *accessor, int deep,
3405                      grn_obj *base_res, grn_obj *res,
3406                      grn_operator op)
3407 {
3408   grn_rc rc = GRN_SUCCESS;
3409   grn_accessor *a;
3410   grn_obj accessor_stack;
3411   int i, n_accessors;
3412   grn_obj *current_res = base_res;
3413 
3414   GRN_PTR_INIT(&accessor_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
3415   n_accessors = 0;
3416   for (a = (grn_accessor *)accessor; a; a = a->next) {
3417     if (deep == n_accessors) {
3418       break;
3419     }
3420     GRN_PTR_PUT(ctx, &accessor_stack, a);
3421     n_accessors++;
3422   }
3423 
3424   for (i = n_accessors; i > 0; i--) {
3425     grn_obj *next_res = NULL;
3426 
3427     a = (grn_accessor *)GRN_PTR_VALUE_AT(&accessor_stack, i - 1);
3428     if (a->obj->header.type == GRN_COLUMN_INDEX) {
3429       rc = grn_accessor_resolve_one_index_column(ctx, a,
3430                                                  current_res, &next_res);
3431     } else if (grn_obj_is_table(ctx, a->obj)) {
3432       rc = grn_accessor_resolve_one_table(ctx, a,
3433                                           current_res, &next_res);
3434     } else {
3435       rc = grn_accessor_resolve_one_data_column(ctx, a,
3436                                                 current_res, &next_res);
3437     }
3438 
3439     if (current_res != base_res) {
3440       grn_obj_unlink(ctx, current_res);
3441     }
3442 
3443     if (rc != GRN_SUCCESS) {
3444       break;
3445     }
3446 
3447     current_res = next_res;
3448   }
3449 
3450   if (rc == GRN_SUCCESS && current_res != base_res) {
3451     grn_id *record_id;
3452     grn_rset_recinfo *recinfo;
3453     GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &record_id, NULL, &recinfo, {
3454       grn_posting posting;
3455       posting.rid = *record_id;
3456       posting.sid = 1;
3457       posting.pos = 0;
3458       posting.weight = recinfo->score - 1;
3459       grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
3460     });
3461     grn_obj_unlink(ctx, current_res);
3462     grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
3463   } else {
3464     if (rc == GRN_SUCCESS) {
3465       rc = GRN_INVALID_ARGUMENT;
3466     }
3467   }
3468 
3469   GRN_OBJ_FIN(ctx, &accessor_stack);
3470   return rc;
3471 }
3472 
3473 static inline void
grn_obj_search_index_report(grn_ctx * ctx,const char * tag,grn_obj * index)3474 grn_obj_search_index_report(grn_ctx *ctx, const char *tag, grn_obj *index)
3475 {
3476   grn_report_index(ctx, "[object][search]", tag, index);
3477 }
3478 
3479 static inline grn_rc
grn_obj_search_accessor(grn_ctx * ctx,grn_obj * obj,grn_obj * query,grn_obj * res,grn_operator op,grn_search_optarg * optarg)3480 grn_obj_search_accessor(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
3481                         grn_obj *res, grn_operator op, grn_search_optarg *optarg)
3482 {
3483   grn_rc rc = GRN_SUCCESS;
3484   grn_accessor *a;
3485   grn_obj *last_obj = NULL;
3486   int n_accessors;
3487 
3488   for (a = (grn_accessor *)obj; a; a = a->next) {
3489     if (!a->next) {
3490       last_obj = a->obj;
3491     }
3492   }
3493   n_accessors = 0;
3494   for (a = (grn_accessor *)obj; a; a = a->next) {
3495     n_accessors++;
3496     if (GRN_OBJ_INDEX_COLUMNP(a->obj)) {
3497       break;
3498     }
3499   }
3500 
3501   {
3502     grn_obj *index;
3503     grn_operator index_op = GRN_OP_MATCH;
3504     if (optarg && optarg->mode != GRN_OP_EXACT) {
3505       index_op = optarg->mode;
3506     }
3507     if (grn_column_index(ctx, last_obj, index_op, &index, 1, NULL) == 0) {
3508       rc = GRN_INVALID_ARGUMENT;
3509       goto exit;
3510     }
3511 
3512     if (n_accessors == 1) {
3513       rc = grn_obj_search(ctx, index, query, res, op, optarg);
3514     } else {
3515       grn_obj *base_res;
3516       grn_obj *range = grn_ctx_at(ctx, DB_OBJ(index)->range);
3517       base_res = grn_table_create(ctx, NULL, 0, NULL,
3518                                   GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3519                                   range,
3520                                   NULL);
3521       rc = ctx->rc;
3522       grn_obj_unlink(ctx, range);
3523       if (!base_res) {
3524         goto exit;
3525       }
3526       if (optarg) {
3527         optarg->match_info.min = GRN_ID_NIL;
3528       }
3529       rc = grn_obj_search(ctx, index, query, base_res, GRN_OP_OR, optarg);
3530       if (rc != GRN_SUCCESS) {
3531         grn_obj_unlink(ctx, base_res);
3532         goto exit;
3533       }
3534       rc = grn_accessor_resolve(ctx, obj, n_accessors - 1, base_res, res, op);
3535       grn_obj_unlink(ctx, base_res);
3536     }
3537   }
3538 
3539 exit :
3540   return rc;
3541 }
3542 
3543 static grn_rc
grn_obj_search_column_index_by_id(grn_ctx * ctx,grn_obj * obj,grn_id tid,grn_obj * res,grn_operator op,grn_search_optarg * optarg)3544 grn_obj_search_column_index_by_id(grn_ctx *ctx, grn_obj *obj,
3545                                   grn_id tid,
3546                                   grn_obj *res, grn_operator op,
3547                                   grn_search_optarg *optarg)
3548 {
3549   grn_ii_cursor *c;
3550 
3551   grn_obj_search_index_report(ctx, "[id]", obj);
3552 
3553   c = grn_ii_cursor_open(ctx, (grn_ii *)obj, tid,
3554                          GRN_ID_NIL, GRN_ID_MAX, 1, 0);
3555   if (c) {
3556     grn_posting *pos;
3557     grn_hash *s = (grn_hash *)res;
3558     while ((pos = grn_ii_cursor_next(ctx, c))) {
3559       /* todo: support orgarg(op)
3560          res_add(ctx, s, (grn_rset_posinfo *) pos,
3561          get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg), op);
3562       */
3563       grn_hash_add(ctx, s, pos, s->key_size, NULL, NULL);
3564     }
3565     grn_ii_cursor_close(ctx, c);
3566   }
3567 
3568   return GRN_SUCCESS;
3569 }
3570 
3571 static grn_rc
grn_obj_search_column_index_by_key(grn_ctx * ctx,grn_obj * obj,grn_obj * query,grn_obj * res,grn_operator op,grn_search_optarg * optarg)3572 grn_obj_search_column_index_by_key(grn_ctx *ctx, grn_obj *obj,
3573                                    grn_obj *query,
3574                                    grn_obj *res, grn_operator op,
3575                                    grn_search_optarg *optarg)
3576 {
3577   grn_rc rc;
3578   unsigned int key_type = GRN_ID_NIL;
3579   const char *key;
3580   unsigned int key_len;
3581   grn_obj *table;
3582   grn_obj casted_query;
3583   grn_bool need_cast = GRN_FALSE;
3584 
3585   table = grn_ctx_at(ctx, obj->header.domain);
3586   if (table) {
3587     key_type = table->header.domain;
3588     need_cast = (query->header.domain != key_type);
3589     grn_obj_unlink(ctx, table);
3590   }
3591   if (need_cast) {
3592     GRN_OBJ_INIT(&casted_query, GRN_BULK, 0, key_type);
3593     rc = grn_obj_cast(ctx, query, &casted_query, GRN_FALSE);
3594     if (rc == GRN_SUCCESS) {
3595       key = GRN_BULK_HEAD(&casted_query);
3596       key_len = GRN_BULK_VSIZE(&casted_query);
3597     }
3598   } else {
3599     rc = GRN_SUCCESS;
3600     key = GRN_BULK_HEAD(query);
3601     key_len = GRN_BULK_VSIZE(query);
3602   }
3603   if (rc == GRN_SUCCESS) {
3604     if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
3605       const char *tag;
3606       if (optarg) {
3607         switch (optarg->mode) {
3608         case GRN_OP_MATCH :
3609           tag = "[key][match]";
3610           break;
3611         case GRN_OP_EXACT :
3612           tag = "[key][exact]";
3613           break;
3614         case GRN_OP_NEAR :
3615           tag = "[key][near]";
3616           break;
3617         case GRN_OP_NEAR2 :
3618           tag = "[key][near2]";
3619           break;
3620         case GRN_OP_SIMILAR :
3621           tag = "[key][similar]";
3622           break;
3623         case GRN_OP_REGEXP :
3624           tag = "[key][regexp]";
3625           break;
3626         case GRN_OP_FUZZY :
3627           tag = "[key][fuzzy]";
3628           break;
3629         default :
3630           tag = "[key][unknown]";
3631           break;
3632         }
3633       } else {
3634         tag = "[key][exact]";
3635       }
3636       grn_obj_search_index_report(ctx, tag, obj);
3637     }
3638     rc = grn_ii_sel(ctx, (grn_ii *)obj, key, key_len,
3639                     (grn_hash *)res, op, optarg);
3640   }
3641   if (need_cast) {
3642     GRN_OBJ_FIN(ctx, &casted_query);
3643   }
3644 
3645   return rc;
3646 }
3647 
3648 static grn_rc
grn_obj_search_column_index(grn_ctx * ctx,grn_obj * obj,grn_obj * query,grn_obj * res,grn_operator op,grn_search_optarg * optarg)3649 grn_obj_search_column_index(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
3650                             grn_obj *res, grn_operator op,
3651                             grn_search_optarg *optarg)
3652 {
3653   grn_rc rc = GRN_INVALID_ARGUMENT;
3654 
3655   if (DB_OBJ(obj)->range == res->header.domain) {
3656     switch (query->header.type) {
3657     case GRN_BULK :
3658       if (query->header.domain == obj->header.domain &&
3659           GRN_BULK_VSIZE(query) == sizeof(grn_id)) {
3660         grn_id tid = GRN_RECORD_VALUE(query);
3661         rc = grn_obj_search_column_index_by_id(ctx, obj, tid, res, op, optarg);
3662       } else {
3663         rc = grn_obj_search_column_index_by_key(ctx, obj, query,
3664                                                 res, op, optarg);
3665       }
3666       break;
3667     case GRN_QUERY :
3668       rc = GRN_FUNCTION_NOT_IMPLEMENTED;
3669       break;
3670     }
3671   }
3672 
3673   return rc;
3674 }
3675 
3676 grn_rc
grn_obj_search(grn_ctx * ctx,grn_obj * obj,grn_obj * query,grn_obj * res,grn_operator op,grn_search_optarg * optarg)3677 grn_obj_search(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
3678                grn_obj *res, grn_operator op, grn_search_optarg *optarg)
3679 {
3680   grn_rc rc = GRN_INVALID_ARGUMENT;
3681   GRN_API_ENTER;
3682   if (GRN_ACCESSORP(obj)) {
3683     rc = grn_obj_search_accessor(ctx, obj, query, res, op, optarg);
3684   } else if (GRN_DB_OBJP(obj)) {
3685     switch (obj->header.type) {
3686     case GRN_TABLE_PAT_KEY :
3687     case GRN_TABLE_DAT_KEY :
3688     case GRN_TABLE_HASH_KEY :
3689       {
3690         const void *key = GRN_BULK_HEAD(query);
3691         uint32_t key_size = GRN_BULK_VSIZE(query);
3692         grn_operator mode = optarg ? optarg->mode : GRN_OP_EXACT;
3693         if (key && key_size) {
3694           if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
3695             const char *tag;
3696             if (optarg) {
3697               switch (optarg->mode) {
3698               case GRN_OP_EXACT :
3699                 tag = "[table][exact]";
3700                 break;
3701               case GRN_OP_LCP :
3702                 tag = "[table][lcp]";
3703                 break;
3704               case GRN_OP_SUFFIX :
3705                 tag = "[table][suffix]";
3706                 break;
3707               case GRN_OP_PREFIX :
3708                 tag = "[table][prefix]";
3709                 break;
3710               case GRN_OP_TERM_EXTRACT :
3711                 tag = "[table][term-extract]";
3712                 break;
3713               case GRN_OP_FUZZY :
3714                 tag = "[table][fuzzy]";
3715                 break;
3716               default :
3717                 tag = "[table][unknown]";
3718                 break;
3719               }
3720             } else {
3721               tag = "[table][exact]";
3722             }
3723             grn_obj_search_index_report(ctx, tag, obj);
3724           }
3725           if (optarg && optarg->mode == GRN_OP_FUZZY) {
3726             rc = grn_table_fuzzy_search(ctx, obj, key, key_size,
3727                                         &(optarg->fuzzy), res, op);
3728           } else {
3729             rc = grn_table_search(ctx, obj, key, key_size, mode, res, op);
3730           }
3731         }
3732       }
3733       break;
3734     case GRN_COLUMN_INDEX :
3735       rc = grn_obj_search_column_index(ctx, obj, query, res, op, optarg);
3736       break;
3737     }
3738   }
3739   GRN_API_RETURN(rc);
3740 }
3741 
3742 #define GRN_TABLE_GROUP_BY_KEY           0
3743 #define GRN_TABLE_GROUP_BY_VALUE         1
3744 #define GRN_TABLE_GROUP_BY_COLUMN_VALUE  2
3745 
3746 #define GRN_TABLE_GROUP_FILTER_PREFIX    0
3747 #define GRN_TABLE_GROUP_FILTER_SUFFIX    (1L<<2)
3748 
3749 inline static void
grn_table_group_add_subrec(grn_ctx * ctx,grn_obj * table,grn_rset_recinfo * ri,double score,grn_rset_posinfo * pi,int dir,grn_obj * calc_target,grn_obj * value_buffer)3750 grn_table_group_add_subrec(grn_ctx *ctx,
3751                            grn_obj *table,
3752                            grn_rset_recinfo *ri, double score,
3753                            grn_rset_posinfo *pi, int dir,
3754                            grn_obj *calc_target,
3755                            grn_obj *value_buffer)
3756 {
3757   grn_table_group_flags flags;
3758 
3759   if (!(DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC)) {
3760     return;
3761   }
3762 
3763   grn_table_add_subrec_inline(table, ri, score, pi, dir);
3764 
3765   flags = DB_OBJ(table)->flags.group;
3766 
3767   if (!(flags & (GRN_TABLE_GROUP_CALC_MAX |
3768                  GRN_TABLE_GROUP_CALC_MIN |
3769                  GRN_TABLE_GROUP_CALC_SUM |
3770                  GRN_TABLE_GROUP_CALC_AVG))) {
3771     return;
3772   }
3773 
3774   GRN_BULK_REWIND(value_buffer);
3775   grn_obj_get_value(ctx, calc_target, pi->rid, value_buffer);
3776   grn_rset_recinfo_update_calc_values(ctx, ri, table, value_buffer);
3777 }
3778 
3779 static grn_bool
accelerated_table_group(grn_ctx * ctx,grn_obj * table,grn_obj * key,grn_table_group_result * result)3780 accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key,
3781                         grn_table_group_result *result)
3782 {
3783   grn_obj *res = result->table;
3784   grn_obj *calc_target = result->calc_target;
3785   if (key->header.type == GRN_ACCESSOR) {
3786     grn_accessor *a = (grn_accessor *)key;
3787     if (a->action == GRN_ACCESSOR_GET_KEY &&
3788         a->next && a->next->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
3789         a->next->obj && !a->next->next) {
3790       grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
3791       int idp = GRN_OBJ_TABLEP(range);
3792       grn_table_cursor *tc;
3793       if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3794         grn_bool processed = GRN_TRUE;
3795         grn_obj value_buffer;
3796         GRN_VOID_INIT(&value_buffer);
3797         switch (a->next->obj->header.type) {
3798         case GRN_COLUMN_FIX_SIZE :
3799           {
3800             grn_id id;
3801             grn_ra *ra = (grn_ra *)a->next->obj;
3802             unsigned int element_size = (ra)->header->element_size;
3803             grn_ra_cache cache;
3804             GRN_RA_CACHE_INIT(ra, &cache);
3805             while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3806               void *v, *value;
3807               grn_id *id_;
3808               uint32_t key_size;
3809               grn_rset_recinfo *ri = NULL;
3810               if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3811                 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3812               }
3813               id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
3814               v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
3815               if (idp && *((grn_id *)v) &&
3816                   grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
3817                 continue;
3818               }
3819               if ((!idp || *((grn_id *)v)) &&
3820                   grn_table_add_v_inline(ctx, res, v, element_size, &value, NULL)) {
3821                 grn_table_group_add_subrec(ctx, res, value,
3822                                            ri ? ri->score : 0,
3823                                            (grn_rset_posinfo *)&id, 0,
3824                                            calc_target,
3825                                            &value_buffer);
3826               }
3827             }
3828             GRN_RA_CACHE_FIN(ra, &cache);
3829           }
3830           break;
3831         case GRN_COLUMN_VAR_SIZE :
3832           if (idp) { /* todo : support other type */
3833             grn_id id;
3834             grn_ja *ja = (grn_ja *)a->next->obj;
3835             while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3836               grn_io_win jw;
3837               unsigned int len = 0;
3838               void *value;
3839               grn_id *v, *id_;
3840               uint32_t key_size;
3841               grn_rset_recinfo *ri = NULL;
3842               if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3843                 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3844               }
3845               id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
3846               if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
3847                 while (len) {
3848                   if ((*v != GRN_ID_NIL) &&
3849                       grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
3850                     grn_table_group_add_subrec(ctx, res, value,
3851                                                ri ? ri->score : 0,
3852                                                (grn_rset_posinfo *)&id, 0,
3853                                                calc_target,
3854                                                &value_buffer);
3855                   }
3856                   v++;
3857                   len -= sizeof(grn_id);
3858                 }
3859                 grn_ja_unref(ctx, &jw);
3860               }
3861             }
3862           } else {
3863             processed = GRN_FALSE;
3864           }
3865           break;
3866         default :
3867           processed = GRN_FALSE;
3868           break;
3869         }
3870         GRN_OBJ_FIN(ctx, &value_buffer);
3871         grn_table_cursor_close(ctx, tc);
3872         return processed;
3873       }
3874     }
3875   }
3876   return GRN_FALSE;
3877 }
3878 
3879 static void
grn_table_group_single_key_records(grn_ctx * ctx,grn_obj * table,grn_obj * key,grn_table_group_result * result)3880 grn_table_group_single_key_records(grn_ctx *ctx, grn_obj *table,
3881                                    grn_obj *key, grn_table_group_result *result)
3882 {
3883   grn_obj bulk;
3884   grn_obj value_buffer;
3885   grn_table_cursor *tc;
3886   grn_obj *res = result->table;
3887   grn_obj *calc_target = result->calc_target;
3888 
3889   GRN_TEXT_INIT(&bulk, 0);
3890   GRN_VOID_INIT(&value_buffer);
3891   if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3892     grn_id id;
3893     grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
3894     int idp = GRN_OBJ_TABLEP(range);
3895     while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3896       void *value;
3897       grn_rset_recinfo *ri = NULL;
3898       GRN_BULK_REWIND(&bulk);
3899       if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3900         grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3901       }
3902       grn_obj_get_value(ctx, key, id, &bulk);
3903       switch (bulk.header.type) {
3904       case GRN_UVECTOR :
3905         {
3906           grn_bool is_reference;
3907           unsigned int element_size;
3908           uint8_t *elements;
3909           int i, n_elements;
3910 
3911           is_reference = !grn_type_id_is_builtin(ctx, bulk.header.type);
3912 
3913           element_size = grn_uvector_element_size(ctx, &bulk);
3914           elements = GRN_BULK_HEAD(&bulk);
3915           n_elements = GRN_BULK_VSIZE(&bulk) / element_size;
3916           for (i = 0; i < n_elements; i++) {
3917             uint8_t *element = elements + (element_size * i);
3918 
3919             if (is_reference) {
3920               grn_id id = *((grn_id *)element);
3921               if (id == GRN_ID_NIL) {
3922                 continue;
3923               }
3924             }
3925 
3926             if (!grn_table_add_v_inline(ctx, res, element, element_size,
3927                                         &value, NULL)) {
3928               continue;
3929             }
3930 
3931             grn_table_group_add_subrec(ctx, res, value,
3932                                        ri ? ri->score : 0,
3933                                        (grn_rset_posinfo *)&id, 0,
3934                                        calc_target,
3935                                        &value_buffer);
3936           }
3937         }
3938         break;
3939       case GRN_VECTOR :
3940         {
3941           unsigned int i, n_elements;
3942           n_elements = grn_vector_size(ctx, &bulk);
3943           for (i = 0; i < n_elements; i++) {
3944             const char *content;
3945             unsigned int content_length;
3946             content_length = grn_vector_get_element(ctx, &bulk, i,
3947                                                     &content, NULL, NULL);
3948             if (grn_table_add_v_inline(ctx, res,
3949                                        content, content_length,
3950                                        &value, NULL)) {
3951               grn_table_group_add_subrec(ctx, res, value,
3952                                          ri ? ri->score : 0,
3953                                          (grn_rset_posinfo *)&id, 0,
3954                                          calc_target,
3955                                          &value_buffer);
3956             }
3957           }
3958         }
3959         break;
3960       case GRN_BULK :
3961         {
3962           if ((!idp || *((grn_id *)GRN_BULK_HEAD(&bulk))) &&
3963               grn_table_add_v_inline(ctx, res,
3964                                      GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
3965                                      &value, NULL)) {
3966             grn_table_group_add_subrec(ctx, res, value,
3967                                        ri ? ri->score : 0,
3968                                        (grn_rset_posinfo *)&id, 0,
3969                                        calc_target,
3970                                        &value_buffer);
3971           }
3972         }
3973         break;
3974       default :
3975         ERR(GRN_INVALID_ARGUMENT, "invalid column");
3976         break;
3977       }
3978     }
3979     grn_table_cursor_close(ctx, tc);
3980   }
3981   GRN_OBJ_FIN(ctx, &value_buffer);
3982   GRN_OBJ_FIN(ctx, &bulk);
3983 }
3984 
3985 #define GRN_TABLE_GROUP_ALL_NAME     "_all"
3986 #define GRN_TABLE_GROUP_ALL_NAME_LEN (sizeof(GRN_TABLE_GROUP_ALL_NAME) - 1)
3987 
3988 static void
grn_table_group_all_records(grn_ctx * ctx,grn_obj * table,grn_table_group_result * result)3989 grn_table_group_all_records(grn_ctx *ctx, grn_obj *table,
3990                             grn_table_group_result *result)
3991 {
3992   grn_obj value_buffer;
3993   grn_table_cursor *tc;
3994   grn_obj *res = result->table;
3995   grn_obj *calc_target = result->calc_target;
3996 
3997   GRN_VOID_INIT(&value_buffer);
3998   if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3999     grn_id id;
4000     void *value;
4001     if (grn_table_add_v_inline(ctx, res,
4002                                GRN_TABLE_GROUP_ALL_NAME,
4003                                GRN_TABLE_GROUP_ALL_NAME_LEN,
4004                                &value, NULL)) {
4005       while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4006         grn_rset_recinfo *ri = NULL;
4007         if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4008           grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4009         }
4010         grn_table_group_add_subrec(ctx, res, value,
4011                                    ri ? ri->score : 0,
4012                                    (grn_rset_posinfo *)&id, 0,
4013                                    calc_target,
4014                                    &value_buffer);
4015       }
4016     }
4017     grn_table_cursor_close(ctx, tc);
4018   }
4019   GRN_OBJ_FIN(ctx, &value_buffer);
4020 }
4021 
4022 grn_rc
grn_table_group_with_range_gap(grn_ctx * ctx,grn_obj * table,grn_table_sort_key * group_key,grn_obj * res,uint32_t range_gap)4023 grn_table_group_with_range_gap(grn_ctx *ctx, grn_obj *table,
4024                                grn_table_sort_key *group_key,
4025                                grn_obj *res, uint32_t range_gap)
4026 {
4027   grn_obj *key = group_key->key;
4028   if (key->header.type == GRN_ACCESSOR) {
4029     grn_accessor *a = (grn_accessor *)key;
4030     if (a->action == GRN_ACCESSOR_GET_KEY &&
4031         a->next && a->next->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
4032         a->next->obj && !a->next->next) {
4033       grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
4034       int idp = GRN_OBJ_TABLEP(range);
4035       grn_table_cursor *tc;
4036       if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL,
4037                                       0, 0, -1, 0))) {
4038         switch (a->next->obj->header.type) {
4039         case GRN_COLUMN_FIX_SIZE :
4040           {
4041             grn_id id;
4042             grn_ra *ra = (grn_ra *)a->next->obj;
4043             unsigned int element_size = (ra)->header->element_size;
4044             grn_ra_cache cache;
4045             GRN_RA_CACHE_INIT(ra, &cache);
4046             while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4047               void *v, *value;
4048               grn_id *id_;
4049               uint32_t key_size;
4050               grn_rset_recinfo *ri = NULL;
4051               if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4052                 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4053               }
4054               id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
4055               v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
4056               if (idp && *((grn_id *)v) &&
4057                   grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
4058                 continue;
4059               }
4060               if ((!idp || *((grn_id *)v))) {
4061                 grn_id id;
4062                 if (element_size == sizeof(uint32_t)) {
4063                   uint32_t quantized = (*(uint32_t *)v);
4064                   quantized -= quantized % range_gap;
4065                   id = grn_table_add_v_inline(ctx, res, &quantized,
4066                                               element_size, &value, NULL);
4067                 } else {
4068                   id = grn_table_add_v_inline(ctx, res, v,
4069                                               element_size, &value, NULL);
4070                 }
4071                 if (id) {
4072                   grn_table_add_subrec_inline(res, value,
4073                                               ri ? ri->score : 0,
4074                                               (grn_rset_posinfo *)&id, 0);
4075                 }
4076               }
4077             }
4078             GRN_RA_CACHE_FIN(ra, &cache);
4079           }
4080           break;
4081         case GRN_COLUMN_VAR_SIZE :
4082           if (idp) { /* todo : support other type */
4083             grn_id id;
4084             grn_ja *ja = (grn_ja *)a->next->obj;
4085             while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4086               grn_io_win jw;
4087               unsigned int len = 0;
4088               void *value;
4089               grn_id *v, *id_;
4090               uint32_t key_size;
4091               grn_rset_recinfo *ri = NULL;
4092               if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4093                 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4094               }
4095               id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
4096               if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
4097                 while (len) {
4098                   if ((*v != GRN_ID_NIL) &&
4099                       grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
4100                     grn_table_add_subrec_inline(res, value, ri ? ri->score : 0,
4101                                                 (grn_rset_posinfo *)&id, 0);
4102                   }
4103                   v++;
4104                   len -= sizeof(grn_id);
4105                 }
4106                 grn_ja_unref(ctx, &jw);
4107               }
4108             }
4109           } else {
4110             return 0;
4111           }
4112           break;
4113         default :
4114           return 0;
4115         }
4116         grn_table_cursor_close(ctx, tc);
4117         GRN_TABLE_GROUPED_ON(res);
4118         return 1;
4119       }
4120     }
4121   }
4122   return 0;
4123 }
4124 
4125 static inline void
grn_table_group_multi_keys_add_record(grn_ctx * ctx,grn_table_sort_key * keys,int n_keys,grn_table_group_result * results,int n_results,grn_id id,grn_rset_recinfo * ri,grn_obj * vector,grn_obj * bulk)4126 grn_table_group_multi_keys_add_record(grn_ctx *ctx,
4127                                       grn_table_sort_key *keys,
4128                                       int n_keys,
4129                                       grn_table_group_result *results,
4130                                       int n_results,
4131                                       grn_id id,
4132                                       grn_rset_recinfo *ri,
4133                                       grn_obj *vector,
4134                                       grn_obj *bulk)
4135 {
4136   int r;
4137   grn_table_group_result *rp;
4138 
4139   for (r = 0, rp = results; r < n_results; r++, rp++) {
4140     void *value;
4141     int i;
4142     int end;
4143 
4144     if (rp->key_end > n_keys) {
4145       end = n_keys;
4146     } else {
4147       end = rp->key_end + 1;
4148     }
4149     GRN_BULK_REWIND(bulk);
4150     grn_text_benc(ctx, bulk, end - rp->key_begin);
4151     for (i = rp->key_begin; i < end; i++) {
4152       grn_section section = vector->u.v.sections[i];
4153       grn_text_benc(ctx, bulk, section.length);
4154     }
4155     {
4156       grn_obj *body = vector->u.v.body;
4157       if (body) {
4158         GRN_TEXT_PUT(ctx, bulk, GRN_BULK_HEAD(body), GRN_BULK_VSIZE(body));
4159       }
4160     }
4161     for (i = rp->key_begin; i < end; i++) {
4162       grn_section section = vector->u.v.sections[i];
4163       grn_text_benc(ctx, bulk, section.weight);
4164       grn_text_benc(ctx, bulk, section.domain);
4165     }
4166 
4167     // todo : cut off GRN_ID_NIL
4168     if (grn_table_add_v_inline(ctx, rp->table,
4169                                GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk),
4170                                &value, NULL)) {
4171       grn_table_group_add_subrec(ctx, rp->table, value,
4172                                  ri ? ri->score : 0,
4173                                  (grn_rset_posinfo *)&id, 0,
4174                                  rp->calc_target,
4175                                  bulk);
4176     }
4177   }
4178 }
4179 
4180 static void
grn_table_group_multi_keys_scalar_records(grn_ctx * ctx,grn_obj * table,grn_table_sort_key * keys,int n_keys,grn_table_group_result * results,int n_results)4181 grn_table_group_multi_keys_scalar_records(grn_ctx *ctx,
4182                                           grn_obj *table,
4183                                           grn_table_sort_key *keys,
4184                                           int n_keys,
4185                                           grn_table_group_result *results,
4186                                           int n_results)
4187 {
4188   grn_id id;
4189   grn_table_cursor *tc;
4190   grn_obj bulk;
4191   grn_obj vector;
4192 
4193   tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
4194   if (!tc) {
4195     return;
4196   }
4197 
4198   GRN_TEXT_INIT(&bulk, 0);
4199   GRN_OBJ_INIT(&vector, GRN_VECTOR, 0, GRN_DB_VOID);
4200   while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4201     int k;
4202     grn_table_sort_key *kp;
4203     grn_rset_recinfo *ri = NULL;
4204 
4205     if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4206       grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4207     }
4208 
4209     GRN_BULK_REWIND(&vector);
4210     for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4211       GRN_BULK_REWIND(&bulk);
4212       grn_obj_get_value(ctx, kp->key, id, &bulk);
4213       grn_vector_add_element(ctx, &vector,
4214                              GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
4215                              0,
4216                              bulk.header.domain);
4217     }
4218 
4219     grn_table_group_multi_keys_add_record(ctx, keys, n_keys, results, n_results,
4220                                           id, ri, &vector, &bulk);
4221   }
4222   GRN_OBJ_FIN(ctx, &vector);
4223   GRN_OBJ_FIN(ctx, &bulk);
4224   grn_table_cursor_close(ctx, tc);
4225 }
4226 
4227 static inline void
grn_table_group_multi_keys_vector_record(grn_ctx * ctx,grn_table_sort_key * keys,grn_obj * key_buffers,int nth_key,int n_keys,grn_table_group_result * results,int n_results,grn_id id,grn_rset_recinfo * ri,grn_obj * vector,grn_obj * bulk)4228 grn_table_group_multi_keys_vector_record(grn_ctx *ctx,
4229                                          grn_table_sort_key *keys,
4230                                          grn_obj *key_buffers,
4231                                          int nth_key,
4232                                          int n_keys,
4233                                          grn_table_group_result *results,
4234                                          int n_results,
4235                                          grn_id id,
4236                                          grn_rset_recinfo *ri,
4237                                          grn_obj *vector,
4238                                          grn_obj *bulk)
4239 {
4240   int k;
4241   grn_table_sort_key *kp;
4242 
4243   for (k = nth_key, kp = &(keys[nth_key]); k < n_keys; k++, kp++) {
4244     grn_obj *key_buffer = &(key_buffers[k]);
4245     switch (key_buffer->header.type) {
4246     case GRN_UVECTOR :
4247       {
4248         unsigned int n_vector_elements;
4249         grn_id domain;
4250         grn_id *ids;
4251         unsigned int i, n_ids;
4252 
4253         n_vector_elements = grn_vector_size(ctx, vector);
4254         domain = key_buffer->header.domain;
4255         ids = (grn_id *)GRN_BULK_HEAD(key_buffer);
4256         n_ids = GRN_BULK_VSIZE(key_buffer) / sizeof(grn_id);
4257         for (i = 0; i < n_ids; i++) {
4258           grn_id element_id = ids[i];
4259           grn_vector_add_element(ctx, vector,
4260                                  (const char *)(&element_id), sizeof(grn_id),
4261                                  0,
4262                                  domain);
4263           grn_table_group_multi_keys_vector_record(ctx,
4264                                                    keys, key_buffers,
4265                                                    k + 1, n_keys,
4266                                                    results, n_results,
4267                                                    id, ri, vector, bulk);
4268           while (grn_vector_size(ctx, vector) != n_vector_elements) {
4269             const char *content;
4270             grn_vector_pop_element(ctx, vector, &content, NULL, NULL);
4271           }
4272         }
4273         return;
4274       }
4275       break;
4276     case GRN_VECTOR :
4277       {
4278         unsigned int n_vector_elements;
4279         unsigned int i, n_key_elements;
4280 
4281         n_vector_elements = grn_vector_size(ctx, vector);
4282         n_key_elements = grn_vector_size(ctx, key_buffer);
4283         for (i = 0; i < n_key_elements; i++) {
4284           const char *content;
4285           unsigned int content_length;
4286           grn_id domain;
4287           content_length = grn_vector_get_element(ctx, key_buffer, i,
4288                                                   &content, NULL, &domain);
4289           grn_vector_add_element(ctx, vector,
4290                                  content, content_length,
4291                                  0,
4292                                  domain);
4293           grn_table_group_multi_keys_vector_record(ctx,
4294                                                    keys, key_buffers,
4295                                                    k + 1, n_keys,
4296                                                    results, n_results,
4297                                                    id, ri, vector, bulk);
4298           while (grn_vector_size(ctx, vector) != n_vector_elements) {
4299             grn_vector_pop_element(ctx, vector, &content, NULL, NULL);
4300           }
4301         }
4302         return;
4303       }
4304       break;
4305     default :
4306       grn_vector_add_element(ctx, vector,
4307                              GRN_BULK_HEAD(key_buffer),
4308                              GRN_BULK_VSIZE(key_buffer),
4309                              0,
4310                              key_buffer->header.domain);
4311     }
4312   }
4313 
4314   if (k == n_keys) {
4315     grn_table_group_multi_keys_add_record(ctx,
4316                                           keys, n_keys,
4317                                           results, n_results,
4318                                           id, ri, vector, bulk);
4319   }
4320 }
4321 
4322 static void
grn_table_group_multi_keys_vector_records(grn_ctx * ctx,grn_obj * table,grn_table_sort_key * keys,int n_keys,grn_table_group_result * results,int n_results)4323 grn_table_group_multi_keys_vector_records(grn_ctx *ctx,
4324                                           grn_obj *table,
4325                                           grn_table_sort_key *keys,
4326                                           int n_keys,
4327                                           grn_table_group_result *results,
4328                                           int n_results)
4329 {
4330   grn_id id;
4331   grn_table_cursor *tc;
4332   grn_obj bulk;
4333   grn_obj vector;
4334   grn_obj *key_buffers;
4335   int k;
4336 
4337   tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
4338   if (!tc) {
4339     return;
4340   }
4341 
4342   key_buffers = GRN_MALLOCN(grn_obj, n_keys);
4343   if (!key_buffers) {
4344     grn_table_cursor_close(ctx, tc);
4345     return;
4346   }
4347 
4348   GRN_TEXT_INIT(&bulk, 0);
4349   GRN_OBJ_INIT(&vector, GRN_VECTOR, 0, GRN_DB_VOID);
4350   for (k = 0; k < n_keys; k++) {
4351     GRN_VOID_INIT(&(key_buffers[k]));
4352   }
4353   while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4354     grn_table_sort_key *kp;
4355     grn_rset_recinfo *ri = NULL;
4356 
4357     if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4358       grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4359     }
4360 
4361     for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4362       grn_obj *key_buffer = &(key_buffers[k]);
4363       GRN_BULK_REWIND(key_buffer);
4364       grn_obj_get_value(ctx, kp->key, id, key_buffer);
4365     }
4366 
4367     GRN_BULK_REWIND(&vector);
4368     grn_table_group_multi_keys_vector_record(ctx,
4369                                              keys, key_buffers, 0, n_keys,
4370                                              results, n_results,
4371                                              id, ri, &vector, &bulk);
4372   }
4373   for (k = 0; k < n_keys; k++) {
4374     GRN_OBJ_FIN(ctx, &(key_buffers[k]));
4375   }
4376   GRN_FREE(key_buffers);
4377   GRN_OBJ_FIN(ctx, &vector);
4378   GRN_OBJ_FIN(ctx, &bulk);
4379   grn_table_cursor_close(ctx, tc);
4380 }
4381 
4382 grn_rc
grn_table_group(grn_ctx * ctx,grn_obj * table,grn_table_sort_key * keys,int n_keys,grn_table_group_result * results,int n_results)4383 grn_table_group(grn_ctx *ctx, grn_obj *table,
4384                 grn_table_sort_key *keys, int n_keys,
4385                 grn_table_group_result *results, int n_results)
4386 {
4387   grn_rc rc = GRN_SUCCESS;
4388   grn_bool group_by_all_records = GRN_FALSE;
4389   if (n_keys == 0 && n_results == 1) {
4390     group_by_all_records = GRN_TRUE;
4391   } else if (!table || !n_keys || !n_results) {
4392     ERR(GRN_INVALID_ARGUMENT, "table or n_keys or n_results is void");
4393     return GRN_INVALID_ARGUMENT;
4394   }
4395   GRN_API_ENTER;
4396   {
4397     int k, r;
4398     grn_table_sort_key *kp;
4399     grn_table_group_result *rp;
4400     for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4401       if ((kp->flags & GRN_TABLE_GROUP_BY_COLUMN_VALUE) && !kp->key) {
4402         ERR(GRN_INVALID_ARGUMENT, "column missing in (%d)", k);
4403         goto exit;
4404       }
4405     }
4406     for (r = 0, rp = results; r < n_results; r++, rp++) {
4407       if (!rp->table) {
4408         grn_table_flags flags;
4409         grn_obj *key_type = NULL;
4410         uint32_t additional_value_size;
4411 
4412         flags = GRN_TABLE_HASH_KEY|
4413           GRN_OBJ_WITH_SUBREC|
4414           GRN_OBJ_UNIT_USERDEF_DOCUMENT;
4415         if (group_by_all_records) {
4416           key_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
4417         } else if (n_keys == 1) {
4418           key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, keys[0].key));
4419         } else {
4420           flags |= GRN_OBJ_KEY_VAR_SIZE;
4421         }
4422         additional_value_size = grn_rset_recinfo_calc_values_size(ctx,
4423                                                                   rp->flags);
4424         rp->table = grn_table_create_with_max_n_subrecs(ctx, NULL, 0, NULL,
4425                                                         flags,
4426                                                         key_type, table,
4427                                                         rp->max_n_subrecs,
4428                                                         additional_value_size);
4429         if (key_type) {
4430           grn_obj_unlink(ctx, key_type);
4431         }
4432         if (!rp->table) {
4433           goto exit;
4434         }
4435         DB_OBJ(rp->table)->flags.group = rp->flags;
4436       }
4437     }
4438     if (group_by_all_records) {
4439       grn_table_group_all_records(ctx, table, results);
4440     } else if (n_keys == 1 && n_results == 1) {
4441       if (!accelerated_table_group(ctx, table, keys->key, results)) {
4442         grn_table_group_single_key_records(ctx, table, keys->key, results);
4443       }
4444     } else {
4445       grn_bool have_vector = GRN_FALSE;
4446       for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4447         grn_id range_id;
4448         grn_obj_flags range_flags = 0;
4449         grn_obj_get_range_info(ctx, kp->key, &range_id, &range_flags);
4450         if (range_flags == GRN_OBJ_VECTOR) {
4451           have_vector = GRN_TRUE;
4452           break;
4453         }
4454       }
4455       if (have_vector) {
4456         grn_table_group_multi_keys_vector_records(ctx, table,
4457                                                   keys, n_keys,
4458                                                   results, n_results);
4459       } else {
4460         grn_table_group_multi_keys_scalar_records(ctx, table,
4461                                                   keys, n_keys,
4462                                                   results, n_results);
4463       }
4464     }
4465     for (r = 0, rp = results; r < n_results; r++, rp++) {
4466       GRN_TABLE_GROUPED_ON(rp->table);
4467     }
4468   }
4469 exit :
4470   GRN_API_RETURN(rc);
4471 }
4472 
4473 grn_rc
grn_table_setoperation(grn_ctx * ctx,grn_obj * table1,grn_obj * table2,grn_obj * res,grn_operator op)4474 grn_table_setoperation(grn_ctx *ctx, grn_obj *table1, grn_obj *table2, grn_obj *res,
4475                        grn_operator op)
4476 {
4477   void *key = NULL, *value1 = NULL, *value2 = NULL;
4478   uint32_t value_size = 0;
4479   uint32_t key_size = 0;
4480   grn_bool have_subrec;
4481 
4482   GRN_API_ENTER;
4483   if (!table1) {
4484     ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] table1 is NULL");
4485     GRN_API_RETURN(ctx->rc);
4486   }
4487   if (!table2) {
4488     ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] table2 is NULL");
4489     GRN_API_RETURN(ctx->rc);
4490   }
4491   if (!res) {
4492     ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] result table is NULL");
4493     GRN_API_RETURN(ctx->rc);
4494   }
4495 
4496   if (table1 != res) {
4497     if (table2 == res) {
4498       grn_obj *t = table1;
4499       table1 = table2;
4500       table2 = t;
4501     } else {
4502       ERR(GRN_INVALID_ARGUMENT,
4503           "[table][setoperation] table1 or table2 must be result table");
4504       GRN_API_RETURN(ctx->rc);
4505     }
4506   }
4507   have_subrec = ((DB_OBJ(table1)->header.flags & GRN_OBJ_WITH_SUBREC) &&
4508                  (DB_OBJ(table2)->header.flags & GRN_OBJ_WITH_SUBREC));
4509   switch (table1->header.type) {
4510   case GRN_TABLE_HASH_KEY :
4511     value_size = ((grn_hash *)table1)->value_size;
4512     break;
4513   case GRN_TABLE_PAT_KEY :
4514     value_size = ((grn_pat *)table1)->value_size;
4515     break;
4516   case GRN_TABLE_DAT_KEY :
4517     value_size = 0;
4518     break;
4519   case GRN_TABLE_NO_KEY :
4520     value_size = ((grn_array *)table1)->value_size;
4521     break;
4522   }
4523   switch (table2->header.type) {
4524   case GRN_TABLE_HASH_KEY :
4525     if (value_size < ((grn_hash *)table2)->value_size) {
4526       value_size = ((grn_hash *)table2)->value_size;
4527     }
4528     break;
4529   case GRN_TABLE_PAT_KEY :
4530     if (value_size < ((grn_pat *)table2)->value_size) {
4531       value_size = ((grn_pat *)table2)->value_size;
4532     }
4533     break;
4534   case GRN_TABLE_DAT_KEY :
4535     value_size = 0;
4536     break;
4537   case GRN_TABLE_NO_KEY :
4538     if (value_size < ((grn_array *)table2)->value_size) {
4539       value_size = ((grn_array *)table2)->value_size;
4540     }
4541     break;
4542   }
4543   switch (op) {
4544   case GRN_OP_OR :
4545     if (have_subrec) {
4546       int added;
4547       GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4548         if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, &added)) {
4549           if (added) {
4550             grn_memcpy(value1, value2, value_size);
4551           } else {
4552             grn_rset_recinfo *ri1 = value1;
4553             grn_rset_recinfo *ri2 = value2;
4554             grn_table_add_subrec_inline(table1, ri1, ri2->score, NULL, 0);
4555           }
4556         }
4557       });
4558     } else {
4559       GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4560         if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, NULL)) {
4561           grn_memcpy(value1, value2, value_size);
4562         }
4563       });
4564     }
4565     break;
4566   case GRN_OP_AND :
4567     if (have_subrec) {
4568       GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
4569         if (grn_table_get_v(ctx, table2, key, key_size, &value2)) {
4570           grn_rset_recinfo *ri1 = value1;
4571           grn_rset_recinfo *ri2 = value2;
4572           ri1->score += ri2->score;
4573         } else {
4574           _grn_table_delete_by_id(ctx, table1, id, NULL);
4575         }
4576       });
4577     } else {
4578       GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
4579         if (!grn_table_get_v(ctx, table2, key, key_size, &value2)) {
4580           _grn_table_delete_by_id(ctx, table1, id, NULL);
4581         }
4582       });
4583     }
4584     break;
4585   case GRN_OP_AND_NOT :
4586     GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4587       grn_table_delete(ctx, table1, key, key_size);
4588     });
4589     break;
4590   case GRN_OP_ADJUST :
4591     if (have_subrec) {
4592       GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4593         if (grn_table_get_v(ctx, table1, key, key_size, &value1)) {
4594           grn_rset_recinfo *ri1 = value1;
4595           grn_rset_recinfo *ri2 = value2;
4596           ri1->score += ri2->score;
4597         }
4598       });
4599     } else {
4600       GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4601         if (grn_table_get_v(ctx, table1, key, key_size, &value1)) {
4602           grn_memcpy(value1, value2, value_size);
4603         }
4604       });
4605     }
4606     break;
4607   default :
4608     break;
4609   }
4610   GRN_API_RETURN(ctx->rc);
4611 }
4612 
4613 grn_rc
grn_table_difference(grn_ctx * ctx,grn_obj * table1,grn_obj * table2,grn_obj * res1,grn_obj * res2)4614 grn_table_difference(grn_ctx *ctx, grn_obj *table1, grn_obj *table2,
4615                      grn_obj *res1, grn_obj *res2)
4616 {
4617   void *key = NULL;
4618   uint32_t key_size = 0;
4619   if (table1 != res1 || table2 != res2) { return GRN_INVALID_ARGUMENT; }
4620   if (grn_table_size(ctx, table1) > grn_table_size(ctx, table2)) {
4621     GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, NULL, {
4622       grn_id id1;
4623       if ((id1 = grn_table_get(ctx, table1, key, key_size))) {
4624         _grn_table_delete_by_id(ctx, table1, id1, NULL);
4625         _grn_table_delete_by_id(ctx, table2, id, NULL);
4626       }
4627     });
4628   } else {
4629     GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, NULL, {
4630       grn_id id2;
4631       if ((id2 = grn_table_get(ctx, table2, key, key_size))) {
4632         _grn_table_delete_by_id(ctx, table1, id, NULL);
4633         _grn_table_delete_by_id(ctx, table2, id2, NULL);
4634       }
4635     });
4636   }
4637   return GRN_SUCCESS;
4638 }
4639 
4640 static grn_obj *grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj,
4641                                      const char *name, unsigned int name_size);
4642 
4643 static grn_obj *
grn_obj_column_(grn_ctx * ctx,grn_obj * table,const char * name,unsigned int name_size)4644 grn_obj_column_(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
4645 {
4646   grn_id table_id = DB_OBJ(table)->id;
4647   grn_obj *column = NULL;
4648 
4649   if (table_id & GRN_OBJ_TMP_OBJECT) {
4650     char column_name[GRN_TABLE_MAX_KEY_SIZE];
4651     void *value = NULL;
4652     grn_snprintf(column_name, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
4653                  "%u%c%.*s", table_id, GRN_DB_DELIMITER, name_size, name);
4654     grn_pat_get(ctx, ctx->impl->temporary_columns,
4655                 column_name, strlen(column_name),
4656                 &value);
4657     if (value) {
4658       column = *((grn_obj **)value);
4659     }
4660   } else {
4661     char buf[GRN_TABLE_MAX_KEY_SIZE];
4662     int len = grn_obj_name(ctx, table, buf, GRN_TABLE_MAX_KEY_SIZE);
4663     if (len) {
4664       buf[len++] = GRN_DB_DELIMITER;
4665       if (len + name_size <= GRN_TABLE_MAX_KEY_SIZE) {
4666         grn_memcpy(buf + len, name, name_size);
4667         column = grn_ctx_get(ctx, buf, len + name_size);
4668       } else {
4669         ERR(GRN_INVALID_ARGUMENT, "name is too long");
4670       }
4671     }
4672   }
4673 
4674   return column;
4675 }
4676 
4677 grn_obj *
grn_obj_column(grn_ctx * ctx,grn_obj * table,const char * name,unsigned int name_size)4678 grn_obj_column(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
4679 {
4680   grn_obj *column = NULL;
4681   GRN_API_ENTER;
4682   if (GRN_OBJ_TABLEP(table)) {
4683     if (grn_db_check_name(ctx, name, name_size) ||
4684         !(column = grn_obj_column_(ctx, table, name, name_size))) {
4685       column = grn_obj_get_accessor(ctx, table, name, name_size);
4686     }
4687   } else if (GRN_ACCESSORP(table)) {
4688     column = grn_obj_get_accessor(ctx, table, name, name_size);
4689   }
4690   GRN_API_RETURN(column);
4691 }
4692 
4693 int
grn_table_columns(grn_ctx * ctx,grn_obj * table,const char * name,unsigned int name_size,grn_obj * res)4694 grn_table_columns(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size,
4695                   grn_obj *res)
4696 {
4697   int n = 0;
4698   grn_id id;
4699 
4700   GRN_API_ENTER;
4701 
4702   if (!GRN_OBJ_TABLEP(table)) {
4703     GRN_API_RETURN(n);
4704   }
4705 
4706   id = DB_OBJ(table)->id;
4707 
4708   if (id == GRN_ID_NIL) {
4709     GRN_API_RETURN(n);
4710   }
4711 
4712   if (id & GRN_OBJ_TMP_OBJECT) {
4713     char search_key[GRN_TABLE_MAX_KEY_SIZE];
4714     grn_pat_cursor *cursor;
4715     grn_snprintf(search_key, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
4716                  "%u%c%.*s", id, GRN_DB_DELIMITER, name_size, name);
4717     cursor = grn_pat_cursor_open(ctx, ctx->impl->temporary_columns,
4718                                  search_key, strlen(search_key),
4719                                  NULL, 0,
4720                                  0, -1, GRN_CURSOR_PREFIX);
4721     if (cursor) {
4722       grn_id column_id;
4723       while ((column_id = grn_pat_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
4724         column_id |= GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN;
4725         grn_hash_add(ctx, (grn_hash *)res,
4726                      &column_id, sizeof(grn_id),
4727                      NULL, NULL);
4728         n++;
4729       }
4730       grn_pat_cursor_close(ctx, cursor);
4731     }
4732   } else {
4733     grn_db *s = (grn_db *)DB_OBJ(table)->db;
4734     if (s->keys) {
4735       grn_obj bulk;
4736       GRN_TEXT_INIT(&bulk, 0);
4737       grn_table_get_key2(ctx, s->keys, id, &bulk);
4738       GRN_TEXT_PUTC(ctx, &bulk, GRN_DB_DELIMITER);
4739       grn_bulk_write(ctx, &bulk, name, name_size);
4740       grn_table_search(ctx, s->keys, GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
4741                        GRN_OP_PREFIX, res, GRN_OP_OR);
4742       grn_obj_close(ctx, &bulk);
4743       n = grn_table_size(ctx, res);
4744     }
4745   }
4746 
4747   GRN_API_RETURN(n);
4748 }
4749 
4750 const char *
_grn_table_key(grn_ctx * ctx,grn_obj * table,grn_id id,uint32_t * key_size)4751 _grn_table_key(grn_ctx *ctx, grn_obj *table, grn_id id, uint32_t *key_size)
4752 {
4753   GRN_ASSERT(table);
4754   if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
4755   switch (table->header.type) {
4756   case GRN_TABLE_HASH_KEY :
4757     return _grn_hash_key(ctx, (grn_hash *)table, id, key_size);
4758   case GRN_TABLE_PAT_KEY :
4759     return _grn_pat_key(ctx, (grn_pat *)table, id, key_size);
4760   case GRN_TABLE_DAT_KEY :
4761     return _grn_dat_key(ctx, (grn_dat *)table, id, key_size);
4762   case GRN_TABLE_NO_KEY :
4763     {
4764       grn_array *a = (grn_array *)table;
4765       const char *v;
4766       if (a->obj.header.domain && a->value_size &&
4767           (v = _grn_array_get_value(ctx, a, id))) {
4768         *key_size = a->value_size;
4769         return v;
4770       } else {
4771         *key_size = 0;
4772       }
4773     }
4774     break;
4775   }
4776   return NULL;
4777 }
4778 
4779 /* column */
4780 
4781 grn_obj *
grn_column_create(grn_ctx * ctx,grn_obj * table,const char * name,unsigned int name_size,const char * path,grn_column_flags flags,grn_obj * type)4782 grn_column_create(grn_ctx *ctx, grn_obj *table,
4783                   const char *name, unsigned int name_size,
4784                   const char *path, grn_column_flags flags, grn_obj *type)
4785 {
4786   grn_db *s;
4787   uint32_t value_size;
4788   grn_obj *db= NULL, *res = NULL;
4789   grn_id id = GRN_ID_NIL;
4790   grn_id range = GRN_ID_NIL;
4791   grn_id domain = GRN_ID_NIL;
4792   grn_bool is_persistent_table;
4793   char fullname[GRN_TABLE_MAX_KEY_SIZE];
4794   unsigned int fullname_size;
4795   char buffer[PATH_MAX];
4796 
4797   GRN_API_ENTER;
4798   if (!table) {
4799     ERR(GRN_INVALID_ARGUMENT, "[column][create] table is missing");
4800     goto exit;
4801   }
4802   if (!type) {
4803     ERR(GRN_INVALID_ARGUMENT, "[column][create] type is missing");
4804     goto exit;
4805   }
4806   if (!name || !name_size) {
4807     ERR(GRN_INVALID_ARGUMENT, "[column][create] name is missing");
4808     goto exit;
4809   }
4810   db = DB_OBJ(table)->db;
4811   s = (grn_db *)db;
4812   if (!GRN_DB_P(s)) {
4813     int table_name_len;
4814     char table_name[GRN_TABLE_MAX_KEY_SIZE];
4815     table_name_len = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
4816     ERR(GRN_INVALID_ARGUMENT,
4817         "[column][create] invalid db assigned: <%.*s>.<%.*s>",
4818         table_name_len, table_name, name_size, name);
4819     goto exit;
4820   }
4821 
4822   if (grn_db_check_name(ctx, name, name_size)) {
4823     GRN_DB_CHECK_NAME_ERR("[column][create]", name, name_size);
4824     goto exit;
4825   }
4826 
4827   domain = DB_OBJ(table)->id;
4828   is_persistent_table = !(domain & GRN_OBJ_TMP_OBJECT);
4829 
4830   if (!domain) {
4831     ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
4832         "[column][create] [todo] table-less column isn't supported yet");
4833     goto exit;
4834   }
4835 
4836   {
4837     int table_name_len;
4838     if (is_persistent_table) {
4839       table_name_len = grn_table_get_key(ctx, s->keys, domain,
4840                                          fullname, GRN_TABLE_MAX_KEY_SIZE);
4841     } else {
4842       grn_snprintf(fullname, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
4843                    "%u", domain);
4844       table_name_len = strlen(fullname);
4845     }
4846     if (name_size + 1 + table_name_len > GRN_TABLE_MAX_KEY_SIZE) {
4847       ERR(GRN_INVALID_ARGUMENT,
4848           "[column][create] too long column name: required name_size(%d) < %d"
4849           ": <%.*s>.<%.*s>",
4850           name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - table_name_len,
4851           table_name_len, fullname, name_size, name);
4852       goto exit;
4853     }
4854     fullname[table_name_len] = GRN_DB_DELIMITER;
4855     grn_memcpy(fullname + table_name_len + 1, name, name_size);
4856     fullname_size = table_name_len + 1 + name_size;
4857   }
4858 
4859   range = DB_OBJ(type)->id;
4860   switch (type->header.type) {
4861   case GRN_TYPE :
4862     {
4863       grn_db_obj *t = (grn_db_obj *)type;
4864       flags |= t->header.flags & ~GRN_OBJ_KEY_MASK;
4865       value_size = GRN_TYPE_SIZE(t);
4866     }
4867     break;
4868   case GRN_TABLE_HASH_KEY :
4869   case GRN_TABLE_PAT_KEY :
4870   case GRN_TABLE_DAT_KEY :
4871   case GRN_TABLE_NO_KEY :
4872     value_size = sizeof(grn_id);
4873     break;
4874   default :
4875     /*
4876     if (type == grn_type_any) {
4877       value_size = sizeof(grn_id) + sizeof(grn_id);
4878     }
4879     */
4880     value_size = sizeof(grn_id);
4881   }
4882 
4883   if (is_persistent_table) {
4884     id = grn_obj_register(ctx, db, fullname, fullname_size);
4885     if (ERRP(ctx, GRN_ERROR)) { goto exit; }
4886 
4887     {
4888       uint32_t table_name_size = 0;
4889       const char *table_name;
4890       table_name = _grn_table_key(ctx, ctx->impl->db, domain, &table_name_size);
4891       GRN_LOG(ctx, GRN_LOG_NOTICE,
4892               "DDL:%u:column_create %.*s %.*s",
4893               id,
4894               table_name_size, table_name,
4895               name_size, name);
4896     }
4897   } else {
4898     int added;
4899     id = grn_pat_add(ctx, ctx->impl->temporary_columns,
4900                      fullname, fullname_size, NULL,
4901                      &added);
4902     if (!id) {
4903       ERR(GRN_NO_MEMORY_AVAILABLE,
4904           "[column][create][temporary] "
4905           "failed to register temporary column name: <%.*s>",
4906           fullname_size, fullname);
4907       goto exit;
4908     } else if (!added) {
4909       id = GRN_ID_NIL;
4910       ERR(GRN_NO_MEMORY_AVAILABLE,
4911           "[column][create][temporary] already used name was assigned: <%.*s>",
4912           fullname_size, fullname);
4913       goto exit;
4914     }
4915     id |= GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN;
4916   }
4917 
4918   if (is_persistent_table && flags & GRN_OBJ_PERSISTENT) {
4919     if (!path) {
4920       if (GRN_DB_PERSISTENT_P(db)) {
4921         grn_db_generate_pathname(ctx, db, id, buffer);
4922         path = buffer;
4923       } else {
4924         int table_name_len;
4925         char table_name[GRN_TABLE_MAX_KEY_SIZE];
4926         table_name_len = grn_obj_name(ctx, table, table_name,
4927                                       GRN_TABLE_MAX_KEY_SIZE);
4928         ERR(GRN_INVALID_ARGUMENT,
4929             "[column][create] path not assigned for persistent column"
4930             ": <%.*s>.<%.*s>",
4931             table_name_len, table_name, name_size, name);
4932         goto exit;
4933       }
4934     } else {
4935       flags |= GRN_OBJ_CUSTOM_NAME;
4936     }
4937   } else {
4938     if (path) {
4939       int table_name_len;
4940       char table_name[GRN_TABLE_MAX_KEY_SIZE];
4941       table_name_len = grn_obj_name(ctx, table, table_name,
4942                                     GRN_TABLE_MAX_KEY_SIZE);
4943       ERR(GRN_INVALID_ARGUMENT,
4944           "[column][create] path assigned for temporary column"
4945           ": <%.*s>.<%.*s>",
4946           table_name_len, table_name, name_size, name);
4947       goto exit;
4948     }
4949   }
4950   switch (flags & GRN_OBJ_COLUMN_TYPE_MASK) {
4951   case GRN_OBJ_COLUMN_SCALAR :
4952     if ((flags & GRN_OBJ_KEY_VAR_SIZE) || value_size > sizeof(int64_t)) {
4953       res = (grn_obj *)grn_ja_create(ctx, path, value_size, flags);
4954     } else {
4955       res = (grn_obj *)grn_ra_create(ctx, path, value_size);
4956     }
4957     break;
4958   case GRN_OBJ_COLUMN_VECTOR :
4959     res = (grn_obj *)grn_ja_create(ctx, path, value_size * 30/*todo*/, flags);
4960     //todo : zlib support
4961     break;
4962   case GRN_OBJ_COLUMN_INDEX :
4963     res = (grn_obj *)grn_ii_create(ctx, path, table, flags); //todo : ii layout support
4964     break;
4965   }
4966   if (res) {
4967     DB_OBJ(res)->header.domain = domain;
4968     DB_OBJ(res)->header.impl_flags = 0;
4969     DB_OBJ(res)->range = range;
4970     DB_OBJ(res)->header.flags = flags;
4971     res->header.flags = flags;
4972     if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
4973       _grn_obj_remove(ctx, res, GRN_FALSE);
4974       res = NULL;
4975     } else {
4976       grn_obj_touch(ctx, res, NULL);
4977     }
4978   }
4979 exit :
4980   if (!res && id) { grn_obj_delete_by_id(ctx, db, id, GRN_TRUE); }
4981   GRN_API_RETURN(res);
4982 }
4983 
4984 grn_obj *
grn_column_open(grn_ctx * ctx,grn_obj * table,const char * name,unsigned int name_size,const char * path,grn_obj * type)4985 grn_column_open(grn_ctx *ctx, grn_obj *table,
4986                 const char *name, unsigned int name_size,
4987                 const char *path, grn_obj *type)
4988 {
4989   grn_id domain;
4990   grn_obj *res = NULL;
4991   grn_db *s;
4992   char fullname[GRN_TABLE_MAX_KEY_SIZE];
4993   GRN_API_ENTER;
4994   if (!table || !type || !name || !name_size) {
4995     ERR(GRN_INVALID_ARGUMENT, "missing type or name");
4996     goto exit;
4997   }
4998   s = (grn_db *)DB_OBJ(table)->db;
4999   if (!GRN_DB_P(s)) {
5000     ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
5001     goto exit;
5002   }
5003   if (grn_db_check_name(ctx, name, name_size)) {
5004     GRN_DB_CHECK_NAME_ERR("[column][open]", name, name_size);
5005     goto exit;
5006   }
5007   if ((domain = DB_OBJ(table)->id)) {
5008     int len = grn_table_get_key(ctx, s->keys, domain, fullname, GRN_TABLE_MAX_KEY_SIZE);
5009     if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
5010       ERR(GRN_INVALID_ARGUMENT, "too long column name");
5011       goto exit;
5012     }
5013     fullname[len] = GRN_DB_DELIMITER;
5014     grn_memcpy(fullname + len + 1, name, name_size);
5015     name_size += len + 1;
5016   } else {
5017     ERR(GRN_INVALID_ARGUMENT, "todo : not supported yet");
5018     goto exit;
5019   }
5020   res = grn_ctx_get(ctx, fullname, name_size);
5021   if (res) {
5022     const char *path2 = grn_obj_path(ctx, res);
5023     if (path && (!path2 || strcmp(path, path2))) { goto exit; }
5024   } else if (path) {
5025     uint32_t dbtype = grn_io_detect_type(ctx, path);
5026     if (!dbtype) { goto exit; }
5027     switch (dbtype) {
5028     case GRN_COLUMN_VAR_SIZE :
5029       res = (grn_obj *)grn_ja_open(ctx, path);
5030       break;
5031     case GRN_COLUMN_FIX_SIZE :
5032       res = (grn_obj *)grn_ra_open(ctx, path);
5033       break;
5034     case GRN_COLUMN_INDEX :
5035       res = (grn_obj *)grn_ii_open(ctx, path, table);
5036       break;
5037     }
5038     if (res) {
5039       grn_id id = grn_obj_register(ctx, (grn_obj *)s, fullname, name_size);
5040       DB_OBJ(res)->header.domain = domain;
5041       DB_OBJ(res)->range = DB_OBJ(type)->id;
5042       res->header.flags |= GRN_OBJ_CUSTOM_NAME;
5043       grn_db_obj_init(ctx, (grn_obj *)s, id, DB_OBJ(res));
5044     }
5045   }
5046 exit :
5047   GRN_API_RETURN(res);
5048 }
5049 
5050 /*
5051 typedef struct {
5052   grn_id id;
5053   int flags;
5054 } grn_column_set_value_arg;
5055 
5056 static grn_rc
5057 default_column_set_value(grn_ctx *ctx, grn_proc_ctx *pctx, grn_obj *in, grn_obj *out)
5058 {
5059   grn_user_data *data = grn_proc_ctx_get_local_data(pctx);
5060   if (data) {
5061     grn_column_set_value_arg *arg = data->ptr;
5062     unsigned int value_size = in->u.p.size; //todo
5063     if (!pctx->obj) { return GRN_ID_NIL; }
5064     switch (pctx->obj->header.type) {
5065     case GRN_COLUMN_VAR_SIZE :
5066       return grn_ja_put(ctx, (grn_ja *)pctx->obj, arg->id,
5067                         in->u.p.ptr, value_size, 0, NULL); // todo type->flag
5068     case GRN_COLUMN_FIX_SIZE :
5069       if (((grn_ra *)pctx->obj)->header->element_size < value_size) {
5070         ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", value_size);
5071         return GRN_INVALID_ARGUMENT;
5072       } else {
5073         void *v = grn_ra_ref(ctx, (grn_ra *)pctx->obj, arg->id);
5074         if (!v) {
5075           ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
5076           return GRN_NO_MEMORY_AVAILABLE;
5077         }
5078         grn_memcpy(v, in->u.p.ptr, value_size);
5079         grn_ra_unref(ctx, (grn_ra *)pctx->obj, arg->id);
5080       }
5081       break;
5082     case GRN_COLUMN_INDEX :
5083       // todo : how??
5084       break;
5085     }
5086     return GRN_SUCCESS;
5087   } else {
5088     ERR(GRN_OBJECT_CORRUPT, "grn_proc_ctx_get_local_data failed");
5089     return ctx->rc;
5090   }
5091 }
5092 */
5093 
5094 /**** grn_vector ****/
5095 
5096 //#define VECTOR(obj) ((grn_vector *)obj)
5097 
5098 /*
5099 #define INITIAL_VECTOR_SIZE 256
5100 
5101 int
5102 grn_vector_delimit(grn_ctx *ctx, grn_obj *vector)
5103 {
5104   grn_vector *v = VECTOR(vector);
5105   uint32_t *offsets;
5106   if (!(v->n_entries & (INITIAL_VECTOR_SIZE - 1))) {
5107     offsets = GRN_REALLOC(v->offsets, sizeof(uint32_t) *
5108                           (v->n_entries + INITIAL_VECTOR_SIZE));
5109     if (!offsets) { return -1; }
5110     v->offsets = offsets;
5111   }
5112   v->offsets[v->n_entries] = GRN_BULK_VSIZE(vector);
5113   return ++(v->n_entries);
5114 }
5115 */
5116 
5117 static unsigned int
grn_uvector_element_size_internal(grn_ctx * ctx,grn_obj * uvector)5118 grn_uvector_element_size_internal(grn_ctx *ctx, grn_obj *uvector)
5119 {
5120   unsigned int element_size;
5121 
5122   if (IS_WEIGHT_UVECTOR(uvector)) {
5123     element_size = sizeof(weight_uvector_entry);
5124   } else {
5125     switch (uvector->header.domain) {
5126     case GRN_DB_BOOL :
5127       element_size = sizeof(grn_bool);
5128       break;
5129     case GRN_DB_INT8 :
5130       element_size = sizeof(int8_t);
5131       break;
5132     case GRN_DB_UINT8 :
5133       element_size = sizeof(uint8_t);
5134       break;
5135     case GRN_DB_INT16 :
5136       element_size = sizeof(int16_t);
5137       break;
5138     case GRN_DB_UINT16 :
5139       element_size = sizeof(uint16_t);
5140       break;
5141     case GRN_DB_INT32 :
5142       element_size = sizeof(int32_t);
5143       break;
5144     case GRN_DB_UINT32 :
5145       element_size = sizeof(uint32_t);
5146       break;
5147     case GRN_DB_INT64 :
5148       element_size = sizeof(int64_t);
5149       break;
5150     case GRN_DB_UINT64 :
5151       element_size = sizeof(uint64_t);
5152       break;
5153     case GRN_DB_FLOAT :
5154       element_size = sizeof(double);
5155       break;
5156     case GRN_DB_TIME :
5157       element_size = sizeof(int64_t);
5158       break;
5159     case GRN_DB_TOKYO_GEO_POINT :
5160     case GRN_DB_WGS84_GEO_POINT :
5161       element_size = sizeof(grn_geo_point);
5162       break;
5163     default :
5164       element_size = sizeof(grn_id);
5165       break;
5166     }
5167   }
5168 
5169   return element_size;
5170 }
5171 
5172 static unsigned int
grn_uvector_size_internal(grn_ctx * ctx,grn_obj * uvector)5173 grn_uvector_size_internal(grn_ctx *ctx, grn_obj *uvector)
5174 {
5175   unsigned int element_size;
5176 
5177   element_size = grn_uvector_element_size_internal(ctx, uvector);
5178   return GRN_BULK_VSIZE(uvector) / element_size;
5179 }
5180 
5181 unsigned int
grn_vector_size(grn_ctx * ctx,grn_obj * vector)5182 grn_vector_size(grn_ctx *ctx, grn_obj *vector)
5183 {
5184   unsigned int size;
5185   if (!vector) {
5186     ERR(GRN_INVALID_ARGUMENT, "vector is null");
5187     return 0;
5188   }
5189   GRN_API_ENTER;
5190   switch (vector->header.type) {
5191   case GRN_BULK :
5192     size = GRN_BULK_VSIZE(vector);
5193     break;
5194   case GRN_UVECTOR :
5195     size = grn_uvector_size_internal(ctx, vector);
5196     break;
5197   case GRN_VECTOR :
5198     size = vector->u.v.n_sections;
5199     break;
5200   default :
5201     ERR(GRN_INVALID_ARGUMENT, "not vector");
5202     size = 0;
5203     break;
5204   }
5205   GRN_API_RETURN(size);
5206 }
5207 
5208 static grn_obj *
grn_vector_body(grn_ctx * ctx,grn_obj * v)5209 grn_vector_body(grn_ctx *ctx, grn_obj *v)
5210 {
5211   if (!v) {
5212     ERR(GRN_INVALID_ARGUMENT, "invalid argument");
5213     return NULL;
5214   }
5215   switch (v->header.type) {
5216   case GRN_VECTOR :
5217     if (!v->u.v.body) {
5218       v->u.v.body = grn_obj_open(ctx, GRN_BULK, 0, v->header.domain);
5219     }
5220     return v->u.v.body;
5221   case GRN_BULK :
5222   case GRN_UVECTOR :
5223     return v;
5224   default :
5225     return NULL;
5226   }
5227 }
5228 
5229 unsigned int
grn_vector_get_element(grn_ctx * ctx,grn_obj * vector,unsigned int offset,const char ** str,unsigned int * weight,grn_id * domain)5230 grn_vector_get_element(grn_ctx *ctx, grn_obj *vector,
5231                        unsigned int offset, const char **str,
5232                        unsigned int *weight, grn_id *domain)
5233 {
5234   unsigned int length = 0;
5235   GRN_API_ENTER;
5236   if (!vector || vector->header.type != GRN_VECTOR) {
5237     ERR(GRN_INVALID_ARGUMENT, "invalid vector");
5238     goto exit;
5239   }
5240   if (vector->u.v.n_sections <= offset) {
5241     ERR(GRN_RANGE_ERROR, "offset out of range");
5242     goto exit;
5243   }
5244   {
5245     grn_section *vp = &vector->u.v.sections[offset];
5246     grn_obj *body = grn_vector_body(ctx, vector);
5247     *str = GRN_BULK_HEAD(body) + vp->offset;
5248     if (weight) { *weight = vp->weight; }
5249     if (domain) { *domain = vp->domain; }
5250     length = vp->length;
5251   }
5252 exit :
5253   GRN_API_RETURN(length);
5254 }
5255 
5256 unsigned int
grn_vector_pop_element(grn_ctx * ctx,grn_obj * vector,const char ** str,unsigned int * weight,grn_id * domain)5257 grn_vector_pop_element(grn_ctx *ctx, grn_obj *vector,
5258                        const char **str, unsigned int *weight, grn_id *domain)
5259 {
5260   unsigned int offset, length = 0;
5261   GRN_API_ENTER;
5262   if (!vector || vector->header.type != GRN_VECTOR) {
5263     ERR(GRN_INVALID_ARGUMENT, "invalid vector");
5264     goto exit;
5265   }
5266   if (!vector->u.v.n_sections) {
5267     ERR(GRN_RANGE_ERROR, "offset out of range");
5268     goto exit;
5269   }
5270   offset = --vector->u.v.n_sections;
5271   {
5272     grn_section *vp = &vector->u.v.sections[offset];
5273     grn_obj *body = grn_vector_body(ctx, vector);
5274     *str = GRN_BULK_HEAD(body) + vp->offset;
5275     if (weight) { *weight = vp->weight; }
5276     if (domain) { *domain = vp->domain; }
5277     length = vp->length;
5278     grn_bulk_truncate(ctx, body, vp->offset);
5279   }
5280 exit :
5281   GRN_API_RETURN(length);
5282 }
5283 
5284 #define W_SECTIONS_UNIT 8
5285 #define S_SECTIONS_UNIT (1 << W_SECTIONS_UNIT)
5286 #define M_SECTIONS_UNIT (S_SECTIONS_UNIT - 1)
5287 
5288 grn_rc
grn_vector_delimit(grn_ctx * ctx,grn_obj * v,unsigned int weight,grn_id domain)5289 grn_vector_delimit(grn_ctx *ctx, grn_obj *v, unsigned int weight, grn_id domain)
5290 {
5291   if (v->header.type != GRN_VECTOR) { return GRN_INVALID_ARGUMENT; }
5292   if (!(v->u.v.n_sections & M_SECTIONS_UNIT)) {
5293     grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
5294                                   (v->u.v.n_sections + S_SECTIONS_UNIT));
5295     if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
5296     v->u.v.sections = vp;
5297   }
5298   {
5299     grn_obj *body = grn_vector_body(ctx, v);
5300     grn_section *vp = &v->u.v.sections[v->u.v.n_sections];
5301     vp->offset = v->u.v.n_sections ? vp[-1].offset + vp[-1].length : 0;
5302     vp->length = GRN_BULK_VSIZE(body) - vp->offset;
5303     vp->weight = weight;
5304     vp->domain = domain;
5305   }
5306   v->u.v.n_sections++;
5307   return GRN_SUCCESS;
5308 }
5309 
5310 grn_rc
grn_vector_decode(grn_ctx * ctx,grn_obj * v,const char * data,uint32_t data_size)5311 grn_vector_decode(grn_ctx *ctx, grn_obj *v, const char *data, uint32_t data_size)
5312 {
5313   uint8_t *p = (uint8_t *)data;
5314   uint8_t *pe = p + data_size;
5315   uint32_t n, n0 = v->u.v.n_sections;
5316   GRN_B_DEC(n, p);
5317   if (((n0 + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT) !=
5318       ((n0 + n + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT)) {
5319     grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
5320                                   ((n0 + n + M_SECTIONS_UNIT) & ~M_SECTIONS_UNIT));
5321     if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
5322     v->u.v.sections = vp;
5323   }
5324   {
5325     grn_section *vp;
5326     grn_obj *body = grn_vector_body(ctx, v);
5327     uint32_t offset = GRN_BULK_VSIZE(body);
5328     uint32_t o = 0, l, i;
5329     for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
5330       if (pe <= p) { return GRN_INVALID_ARGUMENT; }
5331       GRN_B_DEC(l, p);
5332       vp->length = l;
5333       vp->offset = offset + o;
5334       vp->weight = 0;
5335       vp->domain = 0;
5336       o += l;
5337     }
5338     if (pe < p + o) { return GRN_INVALID_ARGUMENT; }
5339     grn_bulk_write(ctx, body, (char *)p, o);
5340     p += o;
5341     if (p < pe) {
5342       for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
5343         if (pe <= p) { return GRN_INVALID_ARGUMENT; }
5344         GRN_B_DEC(vp->weight, p);
5345         GRN_B_DEC(vp->domain, p);
5346       }
5347     }
5348   }
5349   v->u.v.n_sections += n;
5350   return GRN_SUCCESS;
5351 }
5352 
5353 grn_rc
grn_vector_add_element(grn_ctx * ctx,grn_obj * vector,const char * str,unsigned int str_len,unsigned int weight,grn_id domain)5354 grn_vector_add_element(grn_ctx *ctx, grn_obj *vector,
5355                        const char *str, unsigned int str_len,
5356                        unsigned int weight, grn_id domain)
5357 {
5358   grn_obj *body;
5359   GRN_API_ENTER;
5360   if (!vector) {
5361     ERR(GRN_INVALID_ARGUMENT, "vector is null");
5362     goto exit;
5363   }
5364   if ((body = grn_vector_body(ctx, vector))) {
5365     grn_bulk_write(ctx, body, str, str_len);
5366     grn_vector_delimit(ctx, vector, weight, domain);
5367   }
5368 exit :
5369   GRN_API_RETURN(ctx->rc);
5370 }
5371 
5372 /*
5373 grn_obj *
5374 grn_sections_to_vector(grn_ctx *ctx, grn_obj *sections)
5375 {
5376   grn_obj *vector = grn_vector_open(ctx, 0);
5377   if (vector) {
5378     grn_section *vp;
5379     int i;
5380     for (i = sections->u.v.n_sections, vp = sections->u.v.sections; i; i--, vp++) {
5381       grn_text_benc(ctx, vector, vp->weight);
5382       grn_text_benc(ctx, vector, vp->domain);
5383       grn_bulk_write(ctx, vector, vp->str, vp->str_len);
5384       grn_vector_delimit(ctx, vector);
5385     }
5386   }
5387   return vector;
5388 }
5389 
5390 grn_obj *
5391 grn_vector_to_sections(grn_ctx *ctx, grn_obj *vector, grn_obj *sections)
5392 {
5393   if (!sections) {
5394     sections = grn_obj_open(ctx, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, 0);
5395   }
5396   if (sections) {
5397     int i, n = grn_vector_size(ctx, vector);
5398     sections->u.v.src = vector;
5399     for (i = 0; i < n; i++) {
5400       unsigned int size;
5401       const uint8_t *pe, *p = (uint8_t *)grn_vector_fetch(ctx, vector, i, &size);
5402       if (p) {
5403         grn_id domain;
5404         unsigned int weight;
5405         pe = p + size;
5406         if (p < pe) {
5407           GRN_B_DEC(weight, p);
5408           if (p < pe) {
5409             GRN_B_DEC(domain, p);
5410             if (p <= pe) {
5411               grn_vector_add(ctx, sections, (char *)p, pe - p, weight, domain);
5412             }
5413           }
5414         }
5415       }
5416     }
5417   }
5418   return sections;
5419 }
5420 */
5421 
5422 /**** uvector ****/
5423 
5424 unsigned int
grn_uvector_size(grn_ctx * ctx,grn_obj * uvector)5425 grn_uvector_size(grn_ctx *ctx, grn_obj *uvector)
5426 {
5427   unsigned int size;
5428 
5429   if (!uvector) {
5430     ERR(GRN_INVALID_ARGUMENT, "uvector must not be NULL");
5431     return 0;
5432   }
5433 
5434   if (uvector->header.type != GRN_UVECTOR) {
5435     grn_obj type_name;
5436     GRN_TEXT_INIT(&type_name, 0);
5437     grn_inspect_type(ctx, &type_name, uvector->header.type);
5438     ERR(GRN_INVALID_ARGUMENT, "must be GRN_UVECTOR: %.*s",
5439         (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
5440     GRN_OBJ_FIN(ctx, &type_name);
5441     return 0;
5442   }
5443 
5444   GRN_API_ENTER;
5445   size = grn_uvector_size_internal(ctx, uvector);
5446   GRN_API_RETURN(size);
5447 }
5448 
5449 unsigned int
grn_uvector_element_size(grn_ctx * ctx,grn_obj * uvector)5450 grn_uvector_element_size(grn_ctx *ctx, grn_obj *uvector)
5451 {
5452   unsigned int element_size;
5453 
5454   if (!uvector) {
5455     ERR(GRN_INVALID_ARGUMENT, "uvector must not be NULL");
5456     return 0;
5457   }
5458 
5459   if (uvector->header.type != GRN_UVECTOR) {
5460     grn_obj type_name;
5461     GRN_TEXT_INIT(&type_name, 0);
5462     grn_inspect_type(ctx, &type_name, uvector->header.type);
5463     ERR(GRN_INVALID_ARGUMENT, "must be GRN_UVECTOR: %.*s",
5464         (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
5465     GRN_OBJ_FIN(ctx, &type_name);
5466     return 0;
5467   }
5468 
5469   GRN_API_ENTER;
5470   element_size = grn_uvector_element_size_internal(ctx, uvector);
5471   GRN_API_RETURN(element_size);
5472 }
5473 
5474 grn_rc
grn_uvector_add_element(grn_ctx * ctx,grn_obj * uvector,grn_id id,unsigned int weight)5475 grn_uvector_add_element(grn_ctx *ctx, grn_obj *uvector,
5476                         grn_id id, unsigned int weight)
5477 {
5478   GRN_API_ENTER;
5479   if (!uvector) {
5480     ERR(GRN_INVALID_ARGUMENT, "uvector is null");
5481     goto exit;
5482   }
5483   if (IS_WEIGHT_UVECTOR(uvector)) {
5484     weight_uvector_entry entry;
5485     entry.id = id;
5486     entry.weight = weight;
5487     grn_bulk_write(ctx, uvector,
5488                    (const char *)&entry, sizeof(weight_uvector_entry));
5489   } else {
5490     grn_bulk_write(ctx, uvector,
5491                    (const char *)&id, sizeof(grn_id));
5492   }
5493 exit :
5494   GRN_API_RETURN(ctx->rc);
5495 }
5496 
5497 grn_id
grn_uvector_get_element(grn_ctx * ctx,grn_obj * uvector,unsigned int offset,unsigned int * weight)5498 grn_uvector_get_element(grn_ctx *ctx, grn_obj *uvector,
5499                         unsigned int offset, unsigned int *weight)
5500 {
5501   grn_id id = GRN_ID_NIL;
5502 
5503   GRN_API_ENTER;
5504   if (!uvector || uvector->header.type != GRN_UVECTOR) {
5505     ERR(GRN_INVALID_ARGUMENT, "invalid uvector");
5506     goto exit;
5507   }
5508 
5509   if (IS_WEIGHT_UVECTOR(uvector)) {
5510     const weight_uvector_entry *entry;
5511     const weight_uvector_entry *entries_start;
5512     const weight_uvector_entry *entries_end;
5513 
5514     entries_start = (const weight_uvector_entry *)GRN_BULK_HEAD(uvector);
5515     entries_end = (const weight_uvector_entry *)GRN_BULK_CURR(uvector);
5516     if (offset > entries_end - entries_start) {
5517       ERR(GRN_RANGE_ERROR, "offset out of range");
5518       goto exit;
5519     }
5520 
5521     entry = entries_start + offset;
5522     id = entry->id;
5523     if (weight) { *weight = entry->weight; }
5524   } else {
5525     const grn_id *ids_start;
5526     const grn_id *ids_end;
5527 
5528     ids_start = (const grn_id *)GRN_BULK_HEAD(uvector);
5529     ids_end = (const grn_id *)GRN_BULK_CURR(uvector);
5530     if (offset > ids_end - ids_start) {
5531       ERR(GRN_RANGE_ERROR, "offset out of range");
5532       goto exit;
5533     }
5534     id = ids_start[offset];
5535     if (weight) { *weight = 0; }
5536   }
5537 exit :
5538   GRN_API_RETURN(id);
5539 }
5540 
5541 /**** accessor ****/
5542 
5543 static grn_accessor *
accessor_new(grn_ctx * ctx)5544 accessor_new(grn_ctx *ctx)
5545 {
5546   grn_accessor *res = GRN_MALLOCN(grn_accessor, 1);
5547   if (res) {
5548     res->header.type = GRN_ACCESSOR;
5549     res->header.impl_flags = GRN_OBJ_ALLOCATED;
5550     res->header.flags = 0;
5551     res->header.domain = GRN_ID_NIL;
5552     res->range = GRN_ID_NIL;
5553     res->action = GRN_ACCESSOR_VOID;
5554     res->offset = 0;
5555     res->obj = NULL;
5556     res->next = NULL;
5557   }
5558   return res;
5559 }
5560 
5561 inline static grn_bool
grn_obj_get_accessor_rset_value(grn_ctx * ctx,grn_obj * obj,grn_accessor ** res,uint8_t action)5562 grn_obj_get_accessor_rset_value(grn_ctx *ctx, grn_obj *obj,
5563                                 grn_accessor **res, uint8_t action)
5564 {
5565   grn_bool succeeded = GRN_FALSE;
5566   grn_accessor **rp;
5567 
5568   for (rp = res; GRN_TRUE; rp = &(*rp)->next) {
5569     *rp = accessor_new(ctx);
5570     (*rp)->obj = obj;
5571 
5572 #define CHECK_GROUP_CALC_FLAG(flag) do {   \
5573       if (GRN_TABLE_IS_GROUPED(obj)) {     \
5574         grn_table_group_flags flags;       \
5575         flags = DB_OBJ(obj)->flags.group;  \
5576         if (flags & flag) {                \
5577           succeeded = GRN_TRUE;            \
5578           (*rp)->action = action;          \
5579           goto exit;                       \
5580         }                                  \
5581       }                                    \
5582     } while(GRN_FALSE)
5583     switch (action) {
5584     case GRN_ACCESSOR_GET_SCORE :
5585       if (DB_OBJ(obj)->header.flags & GRN_OBJ_WITH_SUBREC) {
5586         (*rp)->action = action;
5587         succeeded = GRN_TRUE;
5588         goto exit;
5589       }
5590       break;
5591     case GRN_ACCESSOR_GET_MAX :
5592       CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_MAX);
5593       break;
5594     case GRN_ACCESSOR_GET_MIN :
5595       CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_MIN);
5596       break;
5597     case GRN_ACCESSOR_GET_SUM :
5598       CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_SUM);
5599       break;
5600     case GRN_ACCESSOR_GET_AVG :
5601       CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_AVG);
5602       break;
5603     case GRN_ACCESSOR_GET_NSUBRECS :
5604       if (GRN_TABLE_IS_GROUPED(obj)) {
5605         (*rp)->action = action;
5606         succeeded = GRN_TRUE;
5607         goto exit;
5608       }
5609       break;
5610     }
5611 #undef CHECK_GROUP_CALC_FLAG
5612 
5613     switch (obj->header.type) {
5614     case GRN_TABLE_PAT_KEY :
5615     case GRN_TABLE_DAT_KEY :
5616     case GRN_TABLE_HASH_KEY :
5617       (*rp)->action = GRN_ACCESSOR_GET_KEY;
5618       break;
5619     case GRN_TABLE_NO_KEY :
5620       if (!obj->header.domain) {
5621         goto exit;
5622       }
5623       (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5624       break;
5625     default :
5626       /* lookup failed */
5627       goto exit;
5628     }
5629     if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5630       goto exit;
5631     }
5632   }
5633 
5634 exit :
5635   if (!succeeded) {
5636     grn_obj_close(ctx, (grn_obj *)*res);
5637     *res = NULL;
5638   }
5639 
5640   return succeeded;
5641 }
5642 
5643 static grn_obj *
grn_obj_get_accessor(grn_ctx * ctx,grn_obj * obj,const char * name,unsigned int name_size)5644 grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
5645 {
5646   grn_accessor *res = NULL, **rp = NULL, **rp0 = NULL;
5647   grn_bool is_chained = GRN_FALSE;
5648   if (!obj) { return NULL; }
5649   GRN_API_ENTER;
5650   if (obj->header.type == GRN_ACCESSOR) {
5651     is_chained = GRN_TRUE;
5652     for (rp0 = (grn_accessor **)&obj; *rp0; rp0 = &(*rp0)->next) {
5653       res = *rp0;
5654     }
5655     switch (res->action) {
5656     case GRN_ACCESSOR_GET_KEY :
5657       obj = grn_ctx_at(ctx, res->obj->header.domain);
5658       break;
5659     case GRN_ACCESSOR_GET_VALUE :
5660     case GRN_ACCESSOR_GET_SCORE :
5661     case GRN_ACCESSOR_GET_NSUBRECS :
5662     case GRN_ACCESSOR_GET_MAX :
5663     case GRN_ACCESSOR_GET_MIN :
5664     case GRN_ACCESSOR_GET_SUM :
5665     case GRN_ACCESSOR_GET_AVG :
5666       obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
5667       break;
5668     case GRN_ACCESSOR_GET_COLUMN_VALUE :
5669       obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
5670       break;
5671     case GRN_ACCESSOR_LOOKUP :
5672       /* todo */
5673       break;
5674     case GRN_ACCESSOR_FUNCALL :
5675       /* todo */
5676       break;
5677     }
5678   }
5679   if (!obj) {
5680     res = NULL;
5681     goto exit;
5682   }
5683   {
5684     size_t len;
5685     const char *sp, *se = name + name_size;
5686     if (*name == GRN_DB_DELIMITER) { name++; }
5687     for (sp = name; (len = grn_charlen(ctx, sp, se)); sp += len) {
5688       if (*sp == GRN_DB_DELIMITER) { break; }
5689     }
5690     if (!(len = sp - name)) { goto exit; }
5691     if (*name == GRN_DB_PSEUDO_COLUMN_PREFIX) { /* pseudo column */
5692       int done = 0;
5693       if (len < 2) { goto exit; }
5694       switch (name[1]) {
5695       case 'k' : /* key */
5696         if (len != GRN_COLUMN_NAME_KEY_LEN ||
5697             memcmp(name, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN)) {
5698           goto exit;
5699         }
5700         for (rp = &res; !done; rp = &(*rp)->next) {
5701           *rp = accessor_new(ctx);
5702           (*rp)->obj = obj;
5703           if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(obj)) {
5704             (*rp)->action = GRN_ACCESSOR_GET_KEY;
5705             done++;
5706             break;
5707           }
5708           if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5709             grn_obj_close(ctx, (grn_obj *)res);
5710             res = NULL;
5711             goto exit;
5712           }
5713           switch (obj->header.type) {
5714           case GRN_DB :
5715             (*rp)->action = GRN_ACCESSOR_GET_KEY;
5716             rp = &(*rp)->next;
5717             *rp = accessor_new(ctx);
5718             (*rp)->obj = obj;
5719             (*rp)->action = GRN_ACCESSOR_GET_DB_OBJ;
5720             done++;
5721             break;
5722           case GRN_TYPE :
5723             (*rp)->action = GRN_ACCESSOR_GET_KEY;
5724             done++;
5725             break;
5726           case GRN_TABLE_PAT_KEY :
5727           case GRN_TABLE_DAT_KEY :
5728           case GRN_TABLE_HASH_KEY :
5729             (*rp)->action = GRN_ACCESSOR_GET_KEY;
5730             break;
5731           case GRN_TABLE_NO_KEY :
5732             if (obj->header.domain) {
5733               (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5734               break;
5735             }
5736             /* fallthru */
5737           default :
5738             /* lookup failed */
5739             grn_obj_close(ctx, (grn_obj *)res);
5740             res = NULL;
5741             goto exit;
5742           }
5743         }
5744         break;
5745       case 'i' : /* id */
5746         if (len != GRN_COLUMN_NAME_ID_LEN ||
5747             memcmp(name, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN)) {
5748           goto exit;
5749         }
5750         for (rp = &res; !done; rp = &(*rp)->next) {
5751           *rp = accessor_new(ctx);
5752           (*rp)->obj = obj;
5753           if (!obj->header.domain) {
5754             (*rp)->action = GRN_ACCESSOR_GET_ID;
5755             done++;
5756           } else {
5757             if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5758               grn_obj_close(ctx, (grn_obj *)res);
5759               res = NULL;
5760               goto exit;
5761             }
5762             switch (obj->header.type) {
5763             case GRN_DB :
5764             case GRN_TYPE :
5765               (*rp)->action = GRN_ACCESSOR_GET_ID;
5766               done++;
5767               break;
5768             case GRN_TABLE_PAT_KEY :
5769             case GRN_TABLE_DAT_KEY :
5770             case GRN_TABLE_HASH_KEY :
5771             case GRN_TABLE_NO_KEY :
5772               (*rp)->action = GRN_ACCESSOR_GET_KEY;
5773               break;
5774             default :
5775               /* lookup failed */
5776               grn_obj_close(ctx, (grn_obj *)res);
5777               res = NULL;
5778               goto exit;
5779             }
5780           }
5781         }
5782         break;
5783       case 'v' : /* value */
5784         if (len != GRN_COLUMN_NAME_VALUE_LEN ||
5785             memcmp(name, GRN_COLUMN_NAME_VALUE, GRN_COLUMN_NAME_VALUE_LEN)) {
5786           goto exit;
5787         }
5788         for (rp = &res; !done; rp = &(*rp)->next) {
5789           *rp = accessor_new(ctx);
5790           (*rp)->obj = obj;
5791           if (!obj->header.domain) {
5792             if (DB_OBJ((*rp)->obj)->range) {
5793               (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5794               done++;
5795             } else {
5796               grn_obj_close(ctx, (grn_obj *)res);
5797               res = NULL;
5798               goto exit;
5799             }
5800             done++;
5801           } else {
5802             if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5803               grn_obj_close(ctx, (grn_obj *)res);
5804               res = NULL;
5805               goto exit;
5806             }
5807             switch (obj->header.type) {
5808             case GRN_DB :
5809             case GRN_TYPE :
5810               if (DB_OBJ((*rp)->obj)->range) {
5811                 (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5812                 done++;
5813               } else {
5814                 grn_obj_close(ctx, (grn_obj *)res);
5815                 res = NULL;
5816                 goto exit;
5817               }
5818               break;
5819             case GRN_TABLE_PAT_KEY :
5820             case GRN_TABLE_DAT_KEY :
5821             case GRN_TABLE_HASH_KEY :
5822             case GRN_TABLE_NO_KEY :
5823              (*rp)->action = GRN_ACCESSOR_GET_KEY;
5824               break;
5825             default :
5826               /* lookup failed */
5827               grn_obj_close(ctx, (grn_obj *)res);
5828               res = NULL;
5829               goto exit;
5830             }
5831           }
5832         }
5833         break;
5834       case 's' : /* score, sum */
5835         if (len == GRN_COLUMN_NAME_SCORE_LEN &&
5836             memcmp(name, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN) == 0) {
5837           if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5838                                                GRN_ACCESSOR_GET_SCORE)) {
5839             goto exit;
5840           }
5841         } else if (len == GRN_COLUMN_NAME_SUM_LEN &&
5842                    memcmp(name,
5843                           GRN_COLUMN_NAME_SUM,
5844                           GRN_COLUMN_NAME_SUM_LEN) == 0) {
5845           if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5846                                                GRN_ACCESSOR_GET_SUM)) {
5847             goto exit;
5848           }
5849         } else {
5850           goto exit;
5851         }
5852         break;
5853       case 'n' : /* nsubrecs */
5854         if (len != GRN_COLUMN_NAME_NSUBRECS_LEN ||
5855             memcmp(name,
5856                    GRN_COLUMN_NAME_NSUBRECS,
5857                    GRN_COLUMN_NAME_NSUBRECS_LEN)) {
5858           goto exit;
5859         }
5860         if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5861                                              GRN_ACCESSOR_GET_NSUBRECS)) {
5862           goto exit;
5863         }
5864         break;
5865       case 'm' : /* max, min */
5866         if (len == GRN_COLUMN_NAME_MAX_LEN &&
5867             memcmp(name,
5868                    GRN_COLUMN_NAME_MAX,
5869                    GRN_COLUMN_NAME_MAX_LEN) == 0) {
5870           if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5871                                                GRN_ACCESSOR_GET_MAX)) {
5872             goto exit;
5873           }
5874         } else if (len == GRN_COLUMN_NAME_MIN_LEN &&
5875                    memcmp(name,
5876                           GRN_COLUMN_NAME_MIN,
5877                           GRN_COLUMN_NAME_MIN_LEN) == 0) {
5878           if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5879                                                GRN_ACCESSOR_GET_MIN)) {
5880             goto exit;
5881           }
5882         } else {
5883           goto exit;
5884         }
5885         break;
5886       case 'a' : /* avg */
5887         if (len == GRN_COLUMN_NAME_AVG_LEN &&
5888             memcmp(name,
5889                    GRN_COLUMN_NAME_AVG,
5890                    GRN_COLUMN_NAME_AVG_LEN) == 0) {
5891           if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5892                                                GRN_ACCESSOR_GET_AVG)) {
5893             goto exit;
5894           }
5895         } else {
5896           goto exit;
5897         }
5898         break;
5899       default :
5900         res = NULL;
5901         goto exit;
5902       }
5903     } else {
5904       /* if obj->header.type == GRN_TYPE ... lookup table */
5905       for (rp = &res; ; rp = &(*rp)->next) {
5906         grn_obj *column = grn_obj_column_(ctx, obj, name, len);
5907         if (column) {
5908           *rp = accessor_new(ctx);
5909           (*rp)->obj = column;
5910           /*
5911           switch (column->header.type) {
5912           case GRN_COLUMN_VAR_SIZE :
5913             break;
5914           case GRN_COLUMN_FIX_SIZE :
5915             break;
5916           case GRN_COLUMN_INDEX :
5917             break;
5918           }
5919           */
5920           (*rp)->action = GRN_ACCESSOR_GET_COLUMN_VALUE;
5921           break;
5922         } else {
5923           grn_id next_obj_id;
5924           next_obj_id = obj->header.domain;
5925           if (!next_obj_id) {
5926             // ERR(GRN_INVALID_ARGUMENT, "no such column: <%s>", name);
5927             if (!is_chained) {
5928               grn_obj_close(ctx, (grn_obj *)res);
5929             }
5930             res = NULL;
5931             goto exit;
5932           }
5933           *rp = accessor_new(ctx);
5934           (*rp)->obj = obj;
5935           obj = grn_ctx_at(ctx, next_obj_id);
5936           if (!obj) {
5937             grn_obj_close(ctx, (grn_obj *)res);
5938             res = NULL;
5939             goto exit;
5940           }
5941           switch (obj->header.type) {
5942           case GRN_TABLE_PAT_KEY :
5943           case GRN_TABLE_DAT_KEY :
5944           case GRN_TABLE_HASH_KEY :
5945           case GRN_TABLE_NO_KEY :
5946             (*rp)->action = GRN_ACCESSOR_GET_KEY;
5947             break;
5948           default :
5949             /* lookup failed */
5950             grn_obj_close(ctx, (grn_obj *)res);
5951             res = NULL;
5952             goto exit;
5953           }
5954         }
5955       }
5956     }
5957     if (sp != se) {
5958       if (!grn_obj_get_accessor(ctx, (grn_obj *)res, sp, se - sp)) {
5959         if (!is_chained) {
5960           grn_obj_close(ctx, (grn_obj *)res);
5961           res = NULL;
5962           goto exit;
5963         }
5964       }
5965     }
5966   }
5967   if (rp0) { *rp0 = res; }
5968  exit :
5969   GRN_API_RETURN((grn_obj *)res);
5970 }
5971 
5972 inline static grn_bool
grn_column_is_vector(grn_ctx * ctx,grn_obj * column)5973 grn_column_is_vector(grn_ctx *ctx, grn_obj *column)
5974 {
5975   grn_obj_flags type;
5976 
5977   if (column->header.type != GRN_COLUMN_VAR_SIZE) {
5978     return GRN_FALSE;
5979   }
5980 
5981   type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
5982   return type == GRN_OBJ_COLUMN_VECTOR;
5983 }
5984 
5985 inline static grn_bool
grn_column_is_index(grn_ctx * ctx,grn_obj * column)5986 grn_column_is_index(grn_ctx *ctx, grn_obj *column)
5987 {
5988   grn_obj_flags type;
5989 
5990   if (column->header.type == GRN_ACCESSOR) {
5991     grn_accessor *a;
5992     for (a = (grn_accessor *)column; a; a = a->next) {
5993       if (a->next) {
5994         continue;
5995       }
5996       if (a->action != GRN_ACCESSOR_GET_COLUMN_VALUE) {
5997         return GRN_FALSE;
5998       }
5999 
6000       column = a->obj;
6001     }
6002   }
6003 
6004   if (column->header.type != GRN_COLUMN_INDEX) {
6005     return GRN_FALSE;
6006   }
6007 
6008   type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
6009   return type == GRN_OBJ_COLUMN_INDEX;
6010 }
6011 
6012 inline static void
grn_obj_get_range_info(grn_ctx * ctx,grn_obj * obj,grn_id * range_id,grn_obj_flags * range_flags)6013 grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj,
6014                        grn_id *range_id, grn_obj_flags *range_flags)
6015 {
6016   if (!obj) {
6017     *range_id = GRN_ID_NIL;
6018   } else if (grn_obj_is_proc(ctx, obj)) {
6019     /* TODO */
6020     *range_id = GRN_ID_NIL;
6021   } else if (GRN_DB_OBJP(obj)) {
6022     *range_id = DB_OBJ(obj)->range;
6023     if (grn_column_is_vector(ctx, obj)) {
6024       *range_flags = GRN_OBJ_VECTOR;
6025     }
6026   } else if (obj->header.type == GRN_ACCESSOR) {
6027     grn_accessor *a;
6028     for (a = (grn_accessor *)obj; a; a = a->next) {
6029       switch (a->action) {
6030       case GRN_ACCESSOR_GET_ID :
6031         *range_id = GRN_DB_UINT32;
6032         break;
6033       case GRN_ACCESSOR_GET_VALUE :
6034         if (GRN_DB_OBJP(a->obj)) {
6035           *range_id = DB_OBJ(a->obj)->range;
6036         }
6037         break;
6038       case GRN_ACCESSOR_GET_SCORE :
6039         *range_id = GRN_DB_FLOAT;
6040         break;
6041       case GRN_ACCESSOR_GET_NSUBRECS :
6042         *range_id = GRN_DB_INT32;
6043         break;
6044       case GRN_ACCESSOR_GET_MAX :
6045       case GRN_ACCESSOR_GET_MIN :
6046       case GRN_ACCESSOR_GET_SUM :
6047         *range_id = GRN_DB_INT64;
6048         break;
6049       case GRN_ACCESSOR_GET_AVG :
6050         *range_id = GRN_DB_FLOAT;
6051         break;
6052       case GRN_ACCESSOR_GET_COLUMN_VALUE :
6053         grn_obj_get_range_info(ctx, a->obj, range_id, range_flags);
6054         break;
6055       case GRN_ACCESSOR_GET_KEY :
6056         if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->header.domain; }
6057         break;
6058       default :
6059         if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->range; }
6060         break;
6061       }
6062     }
6063   }
6064 }
6065 
6066 grn_id
grn_obj_get_range(grn_ctx * ctx,grn_obj * obj)6067 grn_obj_get_range(grn_ctx *ctx, grn_obj *obj)
6068 {
6069   grn_id range_id = GRN_ID_NIL;
6070   grn_obj_flags range_flags = 0;
6071 
6072   grn_obj_get_range_info(ctx, obj, &range_id, &range_flags);
6073 
6074   return range_id;
6075 }
6076 
6077 int
grn_obj_is_persistent(grn_ctx * ctx,grn_obj * obj)6078 grn_obj_is_persistent(grn_ctx *ctx, grn_obj *obj)
6079 {
6080   int res = 0;
6081   if (GRN_DB_OBJP(obj)) {
6082     res = IS_TEMP(obj) ? 0 : 1;
6083   } else if (obj->header.type == GRN_ACCESSOR) {
6084     grn_accessor *a;
6085     for (a = (grn_accessor *)obj; a; a = a->next) {
6086       switch (a->action) {
6087       case GRN_ACCESSOR_GET_SCORE :
6088       case GRN_ACCESSOR_GET_NSUBRECS :
6089       case GRN_ACCESSOR_GET_MAX :
6090       case GRN_ACCESSOR_GET_MIN :
6091       case GRN_ACCESSOR_GET_SUM :
6092       case GRN_ACCESSOR_GET_AVG :
6093         res = 0;
6094         break;
6095       case GRN_ACCESSOR_GET_ID :
6096       case GRN_ACCESSOR_GET_VALUE :
6097       case GRN_ACCESSOR_GET_COLUMN_VALUE :
6098       case GRN_ACCESSOR_GET_KEY :
6099         if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
6100         break;
6101       default :
6102         if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
6103         break;
6104       }
6105     }
6106   }
6107   return res;
6108 }
6109 
6110 #define SRC2RECORD() do {\
6111   grn_obj *table = grn_ctx_at(ctx, dest->header.domain);\
6112   if (GRN_OBJ_TABLEP(table)) {\
6113     grn_obj *p_key = src;\
6114     grn_id id;\
6115     if (table->header.type != GRN_TABLE_NO_KEY) {\
6116       grn_obj key;\
6117       GRN_OBJ_INIT(&key, GRN_BULK, 0, table->header.domain);\
6118       if (src->header.domain != table->header.domain) {\
6119         rc = grn_obj_cast(ctx, src, &key, GRN_TRUE);\
6120         p_key = &key;\
6121       }\
6122       if (!rc) {\
6123         if (GRN_BULK_VSIZE(p_key)) {\
6124           if (add_record_if_not_exist) {\
6125             id = grn_table_add_by_key(ctx, table, p_key, NULL);\
6126           } else {\
6127             id = grn_table_get_by_key(ctx, table, p_key);\
6128           }\
6129           if (id) {\
6130             GRN_RECORD_SET(ctx, dest, id);\
6131           } else {\
6132             rc = GRN_INVALID_ARGUMENT;\
6133           }\
6134         } else {\
6135           GRN_RECORD_SET(ctx, dest, GRN_ID_NIL);\
6136         }\
6137       }\
6138       GRN_OBJ_FIN(ctx, &key);\
6139     } else {\
6140       grn_obj record_id;\
6141       GRN_UINT32_INIT(&record_id, 0);\
6142       rc = grn_obj_cast(ctx, src, &record_id, GRN_TRUE);\
6143       if (!rc) {\
6144         id = GRN_UINT32_VALUE(&record_id);\
6145         if (id) {\
6146           GRN_RECORD_SET(ctx, dest, id);\
6147         } else {\
6148           rc = GRN_INVALID_ARGUMENT;\
6149         }\
6150       }\
6151     }\
6152   } else {\
6153     rc = GRN_FUNCTION_NOT_IMPLEMENTED;\
6154   }\
6155 } while (0)
6156 
6157 inline static grn_rc
grn_obj_cast_bool(grn_ctx * ctx,grn_obj * src,grn_obj * dest,grn_bool add_record_if_not_exist)6158 grn_obj_cast_bool(grn_ctx *ctx, grn_obj *src, grn_obj *dest,
6159                   grn_bool add_record_if_not_exist)
6160 {
6161   grn_rc rc = GRN_SUCCESS;
6162 
6163   switch (dest->header.domain) {
6164   case GRN_DB_BOOL :
6165     GRN_BOOL_SET(ctx, dest, GRN_BOOL_VALUE(src));
6166     break;
6167   case GRN_DB_INT8 :
6168     GRN_INT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
6169     break;
6170   case GRN_DB_UINT8 :
6171     GRN_UINT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
6172     break;
6173   case GRN_DB_INT16 :
6174     GRN_INT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
6175     break;
6176   case GRN_DB_UINT16 :
6177     GRN_UINT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
6178     break;
6179   case GRN_DB_INT32 :
6180     GRN_INT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
6181     break;
6182   case GRN_DB_UINT32 :
6183     GRN_UINT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
6184     break;
6185   case GRN_DB_INT64 :
6186     GRN_INT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
6187     break;
6188   case GRN_DB_UINT64 :
6189     GRN_UINT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
6190     break;
6191   case GRN_DB_FLOAT :
6192     GRN_FLOAT_SET(ctx, dest, GRN_BOOL_VALUE(src));
6193     break;
6194   case GRN_DB_TIME :
6195     GRN_TIME_SET(ctx, dest, GRN_BOOL_VALUE(src));
6196     break;
6197   case GRN_DB_SHORT_TEXT :
6198   case GRN_DB_TEXT :
6199   case GRN_DB_LONG_TEXT :
6200     {
6201       const char *bool_text;
6202       bool_text = GRN_BOOL_VALUE(src) ? "true" : "false";
6203       GRN_TEXT_PUTS(ctx, dest, bool_text);
6204     }
6205     break;
6206   case GRN_DB_TOKYO_GEO_POINT :
6207   case GRN_DB_WGS84_GEO_POINT :
6208     rc = GRN_INVALID_ARGUMENT;
6209     break;
6210   default :
6211     SRC2RECORD();
6212     break;
6213   }
6214   return rc;
6215 }
6216 
6217 #define NUM2DEST(getvalue,totext,tobool,totime,tofloat)\
6218   switch (dest->header.domain) {\
6219   case GRN_DB_BOOL :\
6220     tobool(ctx, dest, getvalue(src));\
6221     break;\
6222   case GRN_DB_INT8 :\
6223     GRN_INT8_SET(ctx, dest, getvalue(src));\
6224     break;\
6225   case GRN_DB_UINT8 :\
6226     GRN_UINT8_SET(ctx, dest, getvalue(src));\
6227     break;\
6228   case GRN_DB_INT16 :\
6229     GRN_INT16_SET(ctx, dest, getvalue(src));\
6230     break;\
6231   case GRN_DB_UINT16 :\
6232     GRN_UINT16_SET(ctx, dest, getvalue(src));\
6233     break;\
6234   case GRN_DB_INT32 :\
6235     GRN_INT32_SET(ctx, dest, getvalue(src));\
6236     break;\
6237   case GRN_DB_UINT32 :\
6238     GRN_UINT32_SET(ctx, dest, getvalue(src));\
6239     break;\
6240   case GRN_DB_TIME :\
6241     totime(ctx, dest, getvalue(src));\
6242     break;\
6243   case GRN_DB_INT64 :\
6244     GRN_INT64_SET(ctx, dest, getvalue(src));\
6245     break;\
6246   case GRN_DB_UINT64 :\
6247     GRN_UINT64_SET(ctx, dest, getvalue(src));\
6248     break;\
6249   case GRN_DB_FLOAT :\
6250     tofloat(ctx, dest, getvalue(src));\
6251     break;\
6252   case GRN_DB_SHORT_TEXT :\
6253   case GRN_DB_TEXT :\
6254   case GRN_DB_LONG_TEXT :\
6255     totext(ctx, dest, getvalue(src));\
6256     break;\
6257   case GRN_DB_TOKYO_GEO_POINT :\
6258   case GRN_DB_WGS84_GEO_POINT :\
6259     rc = GRN_INVALID_ARGUMENT;\
6260     break;\
6261   default :\
6262     SRC2RECORD();\
6263     break;\
6264   }
6265 
6266 #define TEXT2DEST(type,tonum,setvalue) do {\
6267   const char *cur, *str = GRN_TEXT_VALUE(src);\
6268   const char *str_end = GRN_BULK_CURR(src);\
6269   type i = tonum(str, str_end, &cur);\
6270   if (cur == str_end) {\
6271     setvalue(ctx, dest, i);\
6272   } else if (cur != str) {\
6273     const char *rest;\
6274     grn_obj buf;\
6275     GRN_VOID_INIT(&buf);\
6276     rc = grn_aton(ctx, str, str_end, &rest, &buf);\
6277     if (!rc) {\
6278       rc = grn_obj_cast(ctx, &buf, dest, add_record_if_not_exist);\
6279     }\
6280     GRN_OBJ_FIN(ctx, &buf);\
6281   } else {\
6282     rc = GRN_INVALID_ARGUMENT;\
6283   }\
6284 } while (0)
6285 
6286 #define NUM2BOOL(ctx, dest, value) GRN_BOOL_SET(ctx, dest, value != 0)
6287 #define FLOAT2BOOL(ctx, dest, value) do {\
6288   double value_ = value;\
6289   GRN_BOOL_SET(ctx, dest, value_ < -DBL_EPSILON || DBL_EPSILON < value_);\
6290 } while (0)
6291 
6292 #define NUM2TIME(ctx, dest, value)\
6293   GRN_TIME_SET(ctx, dest, (long long int)(value) * GRN_TIME_USEC_PER_SEC);
6294 #define TIME2TIME(ctx, dest, value)\
6295   GRN_TIME_SET(ctx, dest, value);
6296 #define FLOAT2TIME(ctx, dest, value) do {\
6297   int64_t usec = llround(value * GRN_TIME_USEC_PER_SEC);\
6298   GRN_TIME_SET(ctx, dest, usec);\
6299 } while (0)
6300 
6301 #define NUM2FLOAT(ctx, dest, value)\
6302   GRN_FLOAT_SET(ctx, dest, value);
6303 #define TIME2FLOAT(ctx, dest, value)\
6304   GRN_FLOAT_SET(ctx, dest, (double)(value) / GRN_TIME_USEC_PER_SEC);
6305 #define FLOAT2FLOAT(ctx, dest, value)\
6306   GRN_FLOAT_SET(ctx, dest, value);
6307 
6308 static grn_rc
grn_obj_cast_record(grn_ctx * ctx,grn_obj * src,grn_obj * dest,grn_bool add_record_if_not_exist)6309 grn_obj_cast_record(grn_ctx *ctx,
6310                     grn_obj *src,
6311                     grn_obj *dest,
6312                     grn_bool add_record_if_not_exist)
6313 {
6314   grn_obj *src_table;
6315   grn_obj *dest_table;
6316   const char *key;
6317   uint32_t key_size;
6318   grn_id dest_id;
6319 
6320   if (src->header.domain == dest->header.domain) {
6321     GRN_RECORD_SET(ctx, dest, GRN_RECORD_VALUE(src));
6322     return GRN_SUCCESS;
6323   }
6324 
6325   src_table = grn_ctx_at(ctx, src->header.domain);
6326   if (!src_table) {
6327     return GRN_INVALID_ARGUMENT;
6328   }
6329   if (src_table->header.type == GRN_TABLE_NO_KEY) {
6330     return GRN_INVALID_ARGUMENT;
6331   }
6332 
6333   dest_table = grn_ctx_at(ctx, dest->header.domain);
6334   if (!dest_table) {
6335     return GRN_INVALID_ARGUMENT;
6336   }
6337   switch (dest_table->header.type) {
6338   case GRN_TABLE_HASH_KEY :
6339   case GRN_TABLE_PAT_KEY :
6340   case GRN_TABLE_DAT_KEY :
6341     break;
6342   default :
6343     return GRN_INVALID_ARGUMENT;
6344   }
6345 
6346   if (GRN_RECORD_VALUE(src) == GRN_ID_NIL) {
6347     GRN_RECORD_SET(ctx, dest, GRN_RECORD_VALUE(src));
6348     return GRN_SUCCESS;
6349   }
6350 
6351   key = _grn_table_key(ctx, src_table, GRN_RECORD_VALUE(src), &key_size);
6352   if (add_record_if_not_exist) {
6353     dest_id = grn_table_add(ctx, dest_table, key, key_size, NULL);
6354   } else {
6355     dest_id = grn_table_get(ctx, dest_table, key, key_size);
6356   }
6357   GRN_RECORD_SET(ctx, dest, dest_id);
6358   return GRN_SUCCESS;
6359 }
6360 
6361 grn_rc
grn_obj_cast(grn_ctx * ctx,grn_obj * src,grn_obj * dest,grn_bool add_record_if_not_exist)6362 grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest,
6363              grn_bool add_record_if_not_exist)
6364 {
6365   grn_rc rc = GRN_SUCCESS;
6366   switch (src->header.domain) {
6367   case GRN_DB_BOOL :
6368     rc = grn_obj_cast_bool(ctx, src, dest, add_record_if_not_exist);
6369     break;
6370   case GRN_DB_INT8 :
6371     NUM2DEST(GRN_INT8_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6372     break;
6373   case GRN_DB_UINT8 :
6374     NUM2DEST(GRN_UINT8_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6375     break;
6376   case GRN_DB_INT16 :
6377     NUM2DEST(GRN_INT16_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6378     break;
6379   case GRN_DB_UINT16 :
6380     NUM2DEST(GRN_UINT16_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6381     break;
6382   case GRN_DB_INT32 :
6383     NUM2DEST(GRN_INT32_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6384     break;
6385   case GRN_DB_UINT32 :
6386     NUM2DEST(GRN_UINT32_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6387     break;
6388   case GRN_DB_INT64 :
6389     NUM2DEST(GRN_INT64_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6390     break;
6391   case GRN_DB_TIME :
6392     NUM2DEST(GRN_TIME_VALUE, grn_text_lltoa, NUM2BOOL, TIME2TIME, TIME2FLOAT);
6393     break;
6394   case GRN_DB_UINT64 :
6395     NUM2DEST(GRN_UINT64_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6396     break;
6397   case GRN_DB_FLOAT :
6398     NUM2DEST(GRN_FLOAT_VALUE, grn_text_ftoa, FLOAT2BOOL, FLOAT2TIME,
6399              FLOAT2FLOAT);
6400     break;
6401   case GRN_DB_SHORT_TEXT :
6402   case GRN_DB_TEXT :
6403   case GRN_DB_LONG_TEXT :
6404     switch (dest->header.domain) {
6405     case GRN_DB_BOOL :
6406       GRN_BOOL_SET(ctx, dest, GRN_TEXT_LEN(src) > 0);
6407       break;
6408     case GRN_DB_INT8 :
6409       TEXT2DEST(int8_t, grn_atoi8, GRN_INT8_SET);
6410       break;
6411     case GRN_DB_UINT8 :
6412       TEXT2DEST(uint8_t, grn_atoui8, GRN_UINT8_SET);
6413       break;
6414     case GRN_DB_INT16 :
6415       TEXT2DEST(int16_t, grn_atoi16, GRN_INT16_SET);
6416       break;
6417     case GRN_DB_UINT16 :
6418       TEXT2DEST(uint16_t, grn_atoui16, GRN_UINT16_SET);
6419       break;
6420     case GRN_DB_INT32 :
6421       TEXT2DEST(int32_t, grn_atoi, GRN_INT32_SET);
6422       break;
6423     case GRN_DB_UINT32 :
6424       TEXT2DEST(uint32_t, grn_atoui, GRN_UINT32_SET);
6425       break;
6426     case GRN_DB_TIME :
6427       {
6428         grn_timeval v;
6429         int len = GRN_TEXT_LEN(src);
6430         char *str = GRN_TEXT_VALUE(src);
6431         if (grn_str2timeval(str, len, &v)) {
6432           double d;
6433           char *end;
6434           grn_obj buf;
6435           GRN_TEXT_INIT(&buf, 0);
6436           GRN_TEXT_PUT(ctx, &buf, str, len);
6437           GRN_TEXT_PUTC(ctx, &buf, '\0');
6438           errno = 0;
6439           d = strtod(GRN_TEXT_VALUE(&buf), &end);
6440           if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
6441             v.tv_sec = d;
6442             v.tv_nsec = ((d - v.tv_sec) * GRN_TIME_NSEC_PER_SEC);
6443           } else {
6444             rc = GRN_INVALID_ARGUMENT;
6445           }
6446           GRN_OBJ_FIN(ctx, &buf);
6447         }
6448         GRN_TIME_SET(ctx, dest,
6449                      GRN_TIME_PACK((int64_t)v.tv_sec,
6450                                    GRN_TIME_NSEC_TO_USEC(v.tv_nsec)));
6451       }
6452       break;
6453     case GRN_DB_INT64 :
6454       TEXT2DEST(int64_t, grn_atoll, GRN_INT64_SET);
6455       break;
6456     case GRN_DB_UINT64 :
6457       TEXT2DEST(int64_t, grn_atoll, GRN_UINT64_SET);
6458       break;
6459     case GRN_DB_FLOAT :
6460       {
6461         double d;
6462         char *end;
6463         grn_obj buf;
6464         GRN_TEXT_INIT(&buf, 0);
6465         GRN_TEXT_PUT(ctx, &buf, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
6466         GRN_TEXT_PUTC(ctx, &buf, '\0');
6467         errno = 0;
6468         d = strtod(GRN_TEXT_VALUE(&buf), &end);
6469         if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
6470           GRN_FLOAT_SET(ctx, dest, d);
6471         } else {
6472           rc = GRN_INVALID_ARGUMENT;
6473         }
6474         GRN_OBJ_FIN(ctx, &buf);
6475       }
6476       break;
6477     case GRN_DB_SHORT_TEXT :
6478     case GRN_DB_TEXT :
6479     case GRN_DB_LONG_TEXT :
6480       GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
6481       break;
6482     case GRN_DB_TOKYO_GEO_POINT :
6483     case GRN_DB_WGS84_GEO_POINT :
6484       {
6485         int latitude, longitude;
6486         double degree;
6487         const char *cur, *str = GRN_TEXT_VALUE(src);
6488         const char *str_end = GRN_BULK_CURR(src);
6489         if (str == str_end) {
6490           GRN_GEO_POINT_SET(ctx, dest, 0, 0);
6491         } else {
6492           char *end;
6493           grn_obj buf, *buf_p = NULL;
6494           latitude = grn_atoi(str, str_end, &cur);
6495           if (cur < str_end && cur[0] == '.') {
6496             GRN_TEXT_INIT(&buf, 0);
6497             GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
6498             GRN_TEXT_PUTC(ctx, &buf, '\0');
6499             buf_p = &buf;
6500             errno = 0;
6501             degree = strtod(GRN_TEXT_VALUE(buf_p), &end);
6502             if (errno) {
6503               rc = GRN_INVALID_ARGUMENT;
6504             } else {
6505               latitude = GRN_GEO_DEGREE2MSEC(degree);
6506               cur = str + (end - GRN_TEXT_VALUE(buf_p));
6507             }
6508           }
6509           if (!rc && (cur[0] == 'x' || cur[0] == ',') && cur + 1 < str_end) {
6510             const char *c = cur + 1;
6511             longitude = grn_atoi(c, str_end, &cur);
6512             if (cur < str_end && cur[0] == '.') {
6513               if (!buf_p) {
6514                 GRN_TEXT_INIT(&buf, 0);
6515                 GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
6516                 GRN_TEXT_PUTC(ctx, &buf, '\0');
6517                 buf_p = &buf;
6518               }
6519               errno = 0;
6520               degree = strtod(GRN_TEXT_VALUE(buf_p) + (c - str), &end);
6521               if (errno) {
6522                 rc = GRN_INVALID_ARGUMENT;
6523               } else {
6524                 longitude = GRN_GEO_DEGREE2MSEC(degree);
6525                 cur = str + (end - GRN_TEXT_VALUE(buf_p));
6526               }
6527             }
6528             if (!rc && cur == str_end) {
6529               if ((GRN_GEO_MIN_LATITUDE <= latitude &&
6530                    latitude <= GRN_GEO_MAX_LATITUDE) &&
6531                   (GRN_GEO_MIN_LONGITUDE <= longitude &&
6532                    longitude <= GRN_GEO_MAX_LONGITUDE)) {
6533                 GRN_GEO_POINT_SET(ctx, dest, latitude, longitude);
6534               } else {
6535                 rc = GRN_INVALID_ARGUMENT;
6536               }
6537             } else {
6538               rc = GRN_INVALID_ARGUMENT;
6539             }
6540           } else {
6541             rc = GRN_INVALID_ARGUMENT;
6542           }
6543           if (buf_p) { GRN_OBJ_FIN(ctx, buf_p); }
6544         }
6545       }
6546       break;
6547     default :
6548       SRC2RECORD();
6549       break;
6550     }
6551     break;
6552   case GRN_DB_TOKYO_GEO_POINT :
6553   case GRN_DB_WGS84_GEO_POINT :
6554     if (src->header.domain == dest->header.domain) {
6555       GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
6556     } else {
6557       int latitude, longitude;
6558       double latitude_in_degree, longitude_in_degree;
6559       GRN_GEO_POINT_VALUE(src, latitude, longitude);
6560       latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
6561       longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
6562       /* TokyoGeoPoint <-> WGS84GeoPoint is based on
6563          http://www.jalan.net/jw/jwp0200/jww0203.do
6564 
6565          jx: longitude in degree in Tokyo Geodetic System.
6566          jy: latitude in degree in Tokyo Geodetic System.
6567          wx: longitude in degree in WGS 84.
6568          wy: latitude in degree in WGS 84.
6569 
6570          jy = wy * 1.000106961 - wx * 0.000017467 - 0.004602017
6571          jx = wx * 1.000083049 + wy * 0.000046047 - 0.010041046
6572 
6573          wy = jy - jy * 0.00010695 + jx * 0.000017464 + 0.0046017
6574          wx = jx - jy * 0.000046038 - jx * 0.000083043 + 0.010040
6575       */
6576       if (dest->header.domain == GRN_DB_TOKYO_GEO_POINT) {
6577         double wgs84_latitude_in_degree = latitude_in_degree;
6578         double wgs84_longitude_in_degree = longitude_in_degree;
6579         int tokyo_latitude, tokyo_longitude;
6580         double tokyo_latitude_in_degree, tokyo_longitude_in_degree;
6581         tokyo_latitude_in_degree =
6582           wgs84_latitude_in_degree * 1.000106961 -
6583           wgs84_longitude_in_degree * 0.000017467 -
6584           0.004602017;
6585         tokyo_longitude_in_degree =
6586           wgs84_longitude_in_degree * 1.000083049 +
6587           wgs84_latitude_in_degree  * 0.000046047 -
6588           0.010041046;
6589         tokyo_latitude = GRN_GEO_DEGREE2MSEC(tokyo_latitude_in_degree);
6590         tokyo_longitude = GRN_GEO_DEGREE2MSEC(tokyo_longitude_in_degree);
6591         GRN_GEO_POINT_SET(ctx, dest, tokyo_latitude, tokyo_longitude);
6592       } else {
6593         double tokyo_latitude_in_degree = latitude_in_degree;
6594         double tokyo_longitude_in_degree = longitude_in_degree;
6595         int wgs84_latitude, wgs84_longitude;
6596         double wgs84_latitude_in_degree, wgs84_longitude_in_degree;
6597         wgs84_latitude_in_degree =
6598           tokyo_latitude_in_degree -
6599           tokyo_latitude_in_degree * 0.00010695 +
6600           tokyo_longitude_in_degree * 0.000017464 +
6601           0.0046017;
6602         wgs84_longitude_in_degree =
6603           tokyo_longitude_in_degree -
6604           tokyo_latitude_in_degree * 0.000046038 -
6605           tokyo_longitude_in_degree * 0.000083043 +
6606           0.010040;
6607         wgs84_latitude = GRN_GEO_DEGREE2MSEC(wgs84_latitude_in_degree);
6608         wgs84_longitude = GRN_GEO_DEGREE2MSEC(wgs84_longitude_in_degree);
6609         GRN_GEO_POINT_SET(ctx, dest, wgs84_latitude, wgs84_longitude);
6610       }
6611     }
6612     break;
6613   case GRN_VOID :
6614     rc = grn_obj_reinit(ctx, dest, dest->header.domain, dest->header.flags);
6615     break;
6616   default :
6617     if (src->header.domain >= GRN_N_RESERVED_TYPES) {
6618       grn_obj *table;
6619       table = grn_ctx_at(ctx, src->header.domain);
6620       switch (table->header.type) {
6621       case GRN_TABLE_HASH_KEY :
6622       case GRN_TABLE_PAT_KEY :
6623       case GRN_TABLE_DAT_KEY :
6624       case GRN_TABLE_NO_KEY :
6625         rc = grn_obj_cast_record(ctx, src, dest, add_record_if_not_exist);
6626         break;
6627       default :
6628         rc = GRN_FUNCTION_NOT_IMPLEMENTED;
6629         break;
6630       }
6631     } else {
6632       rc = GRN_FUNCTION_NOT_IMPLEMENTED;
6633     }
6634     break;
6635   }
6636   return rc;
6637 }
6638 
6639 const char *
grn_accessor_get_value_(grn_ctx * ctx,grn_accessor * a,grn_id id,uint32_t * size)6640 grn_accessor_get_value_(grn_ctx *ctx, grn_accessor *a, grn_id id, uint32_t *size)
6641 {
6642   const char *value = NULL;
6643   for (;;) {
6644     switch (a->action) {
6645     case GRN_ACCESSOR_GET_ID :
6646       value = (const char *)(uintptr_t)id;
6647       *size = GRN_OBJ_GET_VALUE_IMD;
6648       break;
6649     case GRN_ACCESSOR_GET_KEY :
6650       value = _grn_table_key(ctx, a->obj, id, size);
6651       break;
6652     case GRN_ACCESSOR_GET_VALUE :
6653       value = grn_obj_get_value_(ctx, a->obj, id, size);
6654       break;
6655     case GRN_ACCESSOR_GET_SCORE :
6656       if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6657         value = (const char *)&((grn_rset_recinfo *)value)->score;
6658         *size = sizeof(double);
6659       }
6660       break;
6661     case GRN_ACCESSOR_GET_NSUBRECS :
6662       if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6663         value = (const char *)&((grn_rset_recinfo *)value)->n_subrecs;
6664         *size = sizeof(int);
6665       }
6666       break;
6667     case GRN_ACCESSOR_GET_MAX :
6668       if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6669         value =
6670           (const char *)grn_rset_recinfo_get_max_(ctx,
6671                                                   (grn_rset_recinfo *)value,
6672                                                   a->obj);
6673         *size = GRN_RSET_MAX_SIZE;
6674       }
6675       break;
6676     case GRN_ACCESSOR_GET_MIN :
6677       if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6678         value =
6679           (const char *)grn_rset_recinfo_get_min_(ctx,
6680                                                   (grn_rset_recinfo *)value,
6681                                                   a->obj);
6682         *size = GRN_RSET_MIN_SIZE;
6683       }
6684       break;
6685     case GRN_ACCESSOR_GET_SUM :
6686       if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6687         value =
6688           (const char *)grn_rset_recinfo_get_sum_(ctx,
6689                                                   (grn_rset_recinfo *)value,
6690                                                   a->obj);
6691         *size = GRN_RSET_SUM_SIZE;
6692       }
6693       break;
6694     case GRN_ACCESSOR_GET_AVG :
6695       if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6696         value =
6697           (const char *)grn_rset_recinfo_get_avg_(ctx,
6698                                                   (grn_rset_recinfo *)value,
6699                                                   a->obj);
6700         *size = GRN_RSET_AVG_SIZE;
6701       }
6702       break;
6703     case GRN_ACCESSOR_GET_COLUMN_VALUE :
6704       /* todo : support vector */
6705       value = grn_obj_get_value_(ctx, a->obj, id, size);
6706       break;
6707     case GRN_ACCESSOR_GET_DB_OBJ :
6708       value = _grn_table_key(ctx, ((grn_db *)ctx->impl->db)->keys, id, size);
6709       break;
6710     case GRN_ACCESSOR_LOOKUP :
6711       /* todo */
6712       break;
6713     case GRN_ACCESSOR_FUNCALL :
6714       /* todo */
6715       break;
6716     }
6717     if (value && (a = a->next)) {
6718       id = *((grn_id *)value);
6719     } else {
6720       break;
6721     }
6722   }
6723   return value;
6724 }
6725 
6726 static grn_obj *
grn_accessor_get_value(grn_ctx * ctx,grn_accessor * a,grn_id id,grn_obj * value)6727 grn_accessor_get_value(grn_ctx *ctx, grn_accessor *a, grn_id id, grn_obj *value)
6728 {
6729   uint32_t vs = 0;
6730   uint32_t size0;
6731   void *vp = NULL;
6732   if (!value) {
6733     if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) { return NULL; }
6734   } else {
6735     value->header.type = GRN_BULK;
6736   }
6737   size0 = GRN_BULK_VSIZE(value);
6738   for (;;) {
6739     grn_bulk_truncate(ctx, value, size0);
6740     switch (a->action) {
6741     case GRN_ACCESSOR_GET_ID :
6742       GRN_UINT32_PUT(ctx, value, id);
6743       value->header.domain = GRN_DB_UINT32;
6744       vp = GRN_BULK_HEAD(value) + size0;
6745       vs = GRN_BULK_VSIZE(value) - size0;
6746       break;
6747     case GRN_ACCESSOR_GET_KEY :
6748       if (!a->next && GRN_TABLE_IS_MULTI_KEYS_GROUPED(a->obj)) {
6749         grn_obj_ensure_vector(ctx, value);
6750         if (id) {
6751           grn_obj raw_vector;
6752           GRN_TEXT_INIT(&raw_vector, 0);
6753           grn_table_get_key2(ctx, a->obj, id, &raw_vector);
6754           grn_vector_decode(ctx, value,
6755                             GRN_BULK_HEAD(&raw_vector),
6756                             GRN_BULK_VSIZE(&raw_vector));
6757           GRN_OBJ_FIN(ctx, &raw_vector);
6758         }
6759         vp = NULL;
6760         vs = 0;
6761       } else {
6762         if (id) {
6763           grn_table_get_key2(ctx, a->obj, id, value);
6764           vp = GRN_BULK_HEAD(value) + size0;
6765           vs = GRN_BULK_VSIZE(value) - size0;
6766         } else {
6767           vp = NULL;
6768           vs = 0;
6769         }
6770         value->header.domain = a->obj->header.domain;
6771       }
6772       break;
6773     case GRN_ACCESSOR_GET_VALUE :
6774       grn_obj_get_value(ctx, a->obj, id, value);
6775       vp = GRN_BULK_HEAD(value) + size0;
6776       vs = GRN_BULK_VSIZE(value) - size0;
6777       break;
6778     case GRN_ACCESSOR_GET_SCORE :
6779       if (id) {
6780         grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6781         GRN_FLOAT_PUT(ctx, value, ri->score);
6782       } else {
6783         GRN_FLOAT_PUT(ctx, value, 0.0);
6784       }
6785       value->header.domain = GRN_DB_FLOAT;
6786       break;
6787     case GRN_ACCESSOR_GET_NSUBRECS :
6788       if (id) {
6789         grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6790         GRN_INT32_PUT(ctx, value, ri->n_subrecs);
6791       } else {
6792         GRN_INT32_PUT(ctx, value, 0);
6793       }
6794       value->header.domain = GRN_DB_INT32;
6795       break;
6796     case GRN_ACCESSOR_GET_MAX :
6797       if (id) {
6798         grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6799         int64_t max;
6800         max = grn_rset_recinfo_get_max(ctx, ri, a->obj);
6801         GRN_INT64_PUT(ctx, value, max);
6802       } else {
6803         GRN_INT64_PUT(ctx, value, 0);
6804       }
6805       value->header.domain = GRN_DB_INT64;
6806       break;
6807     case GRN_ACCESSOR_GET_MIN :
6808       if (id) {
6809         grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6810         int64_t min;
6811         min = grn_rset_recinfo_get_min(ctx, ri, a->obj);
6812         GRN_INT64_PUT(ctx, value, min);
6813       } else {
6814         GRN_INT64_PUT(ctx, value, 0);
6815       }
6816       value->header.domain = GRN_DB_INT64;
6817       break;
6818     case GRN_ACCESSOR_GET_SUM :
6819       if (id) {
6820         grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6821         int64_t sum;
6822         sum = grn_rset_recinfo_get_sum(ctx, ri, a->obj);
6823         GRN_INT64_PUT(ctx, value, sum);
6824       } else {
6825         GRN_INT64_PUT(ctx, value, 0);
6826       }
6827       value->header.domain = GRN_DB_INT64;
6828       break;
6829     case GRN_ACCESSOR_GET_AVG :
6830       if (id) {
6831         grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6832         double avg;
6833         avg = grn_rset_recinfo_get_avg(ctx, ri, a->obj);
6834         GRN_FLOAT_PUT(ctx, value, avg);
6835       } else {
6836         GRN_FLOAT_PUT(ctx, value, 0.0);
6837       }
6838       value->header.domain = GRN_DB_FLOAT;
6839       break;
6840     case GRN_ACCESSOR_GET_COLUMN_VALUE :
6841       /* todo : support vector */
6842       grn_obj_get_value(ctx, a->obj, id, value);
6843       vp = GRN_BULK_HEAD(value) + size0;
6844       vs = GRN_BULK_VSIZE(value) - size0;
6845       break;
6846     case GRN_ACCESSOR_GET_DB_OBJ :
6847       value = grn_ctx_at(ctx, id);
6848       grn_obj_close(ctx, value);
6849       return value;
6850       break;
6851     case GRN_ACCESSOR_LOOKUP :
6852       /* todo */
6853       break;
6854     case GRN_ACCESSOR_FUNCALL :
6855       /* todo */
6856       break;
6857     }
6858     if ((a = a->next)) {
6859       if (vs > 0) {
6860         id = *((grn_id *)vp);
6861       } else {
6862         id = GRN_ID_NIL;
6863       }
6864     } else {
6865       break;
6866     }
6867   }
6868   return value;
6869 }
6870 
6871 static grn_rc
grn_accessor_set_value(grn_ctx * ctx,grn_accessor * a,grn_id id,grn_obj * value,int flags)6872 grn_accessor_set_value(grn_ctx *ctx, grn_accessor *a, grn_id id,
6873                        grn_obj *value, int flags)
6874 {
6875   grn_rc rc = GRN_SUCCESS;
6876   if (!value) { value = grn_obj_open(ctx, GRN_BULK, 0, 0); }
6877   if (value) {
6878     grn_obj buf;
6879     void *vp = NULL;
6880     GRN_TEXT_INIT(&buf, 0);
6881     for (;;) {
6882       GRN_BULK_REWIND(&buf);
6883       switch (a->action) {
6884       case GRN_ACCESSOR_GET_KEY :
6885         grn_table_get_key2(ctx, a->obj, id, &buf);
6886         vp = GRN_BULK_HEAD(&buf);
6887         break;
6888       case GRN_ACCESSOR_GET_VALUE :
6889         if (a->next) {
6890           grn_obj_get_value(ctx, a->obj, id, &buf);
6891           vp = GRN_BULK_HEAD(&buf);
6892         } else {
6893           rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
6894         }
6895         break;
6896       case GRN_ACCESSOR_GET_SCORE :
6897         {
6898           grn_rset_recinfo *ri;
6899           if (a->next) {
6900             grn_obj_get_value(ctx, a->obj, id, &buf);
6901             ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6902             vp = &ri->score;
6903           } else {
6904             uint32_t size;
6905             if ((ri = (grn_rset_recinfo *) grn_obj_get_value_(ctx, a->obj, id, &size))) {
6906               // todo : flags support
6907               if (value->header.domain == GRN_DB_FLOAT) {
6908                 ri->score = GRN_FLOAT_VALUE(value);
6909               } else {
6910                 grn_obj buf;
6911                 GRN_FLOAT_INIT(&buf, 0);
6912                 grn_obj_cast(ctx, value, &buf, GRN_FALSE);
6913                 ri->score = GRN_FLOAT_VALUE(&buf);
6914                 GRN_OBJ_FIN(ctx, &buf);
6915               }
6916             }
6917           }
6918         }
6919         break;
6920       case GRN_ACCESSOR_GET_NSUBRECS :
6921         grn_obj_get_value(ctx, a->obj, id, &buf);
6922         {
6923           grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6924           vp = &ri->n_subrecs;
6925         }
6926         break;
6927       case GRN_ACCESSOR_GET_MAX :
6928         grn_obj_get_value(ctx, a->obj, id, &buf);
6929         {
6930           grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6931           if (value->header.type == GRN_DB_INT64) {
6932             grn_rset_recinfo_set_max(ctx, ri, a->obj, GRN_INT64_VALUE(value));
6933           } else {
6934             grn_obj value_int64;
6935             GRN_INT64_INIT(&value_int64, 0);
6936             if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
6937               grn_rset_recinfo_set_max(ctx, ri, a->obj,
6938                                        GRN_INT64_VALUE(&value_int64));
6939             }
6940             GRN_OBJ_FIN(ctx, &value_int64);
6941           }
6942         }
6943         break;
6944       case GRN_ACCESSOR_GET_MIN :
6945         grn_obj_get_value(ctx, a->obj, id, &buf);
6946         {
6947           grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6948           if (value->header.type == GRN_DB_INT64) {
6949             grn_rset_recinfo_set_min(ctx, ri, a->obj, GRN_INT64_VALUE(value));
6950           } else {
6951             grn_obj value_int64;
6952             GRN_INT64_INIT(&value_int64, 0);
6953             if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
6954               grn_rset_recinfo_set_min(ctx, ri, a->obj,
6955                                        GRN_INT64_VALUE(&value_int64));
6956             }
6957             GRN_OBJ_FIN(ctx, &value_int64);
6958           }
6959         }
6960         break;
6961       case GRN_ACCESSOR_GET_SUM :
6962         grn_obj_get_value(ctx, a->obj, id, &buf);
6963         {
6964           grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6965           if (value->header.type == GRN_DB_INT64) {
6966             grn_rset_recinfo_set_sum(ctx, ri, a->obj, GRN_INT64_VALUE(value));
6967           } else {
6968             grn_obj value_int64;
6969             GRN_INT64_INIT(&value_int64, 0);
6970             if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
6971               grn_rset_recinfo_set_sum(ctx, ri, a->obj,
6972                                        GRN_INT64_VALUE(&value_int64));
6973             }
6974             GRN_OBJ_FIN(ctx, &value_int64);
6975           }
6976         }
6977         break;
6978       case GRN_ACCESSOR_GET_AVG :
6979         grn_obj_get_value(ctx, a->obj, id, &buf);
6980         {
6981           grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6982           if (value->header.type == GRN_DB_FLOAT) {
6983             grn_rset_recinfo_set_avg(ctx, ri, a->obj, GRN_FLOAT_VALUE(value));
6984           } else {
6985             grn_obj value_float;
6986             GRN_FLOAT_INIT(&value_float, 0);
6987             if (!grn_obj_cast(ctx, value, &value_float, GRN_FALSE)) {
6988               grn_rset_recinfo_set_avg(ctx, ri, a->obj,
6989                                        GRN_FLOAT_VALUE(&value_float));
6990             }
6991             GRN_OBJ_FIN(ctx, &value_float);
6992           }
6993         }
6994         break;
6995       case GRN_ACCESSOR_GET_COLUMN_VALUE :
6996         /* todo : support vector */
6997         if (a->next) {
6998           grn_obj_get_value(ctx, a->obj, id, &buf);
6999           vp = GRN_BULK_HEAD(&buf);
7000         } else {
7001           rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
7002         }
7003         break;
7004       case GRN_ACCESSOR_LOOKUP :
7005         /* todo */
7006         break;
7007       case GRN_ACCESSOR_FUNCALL :
7008         /* todo */
7009         break;
7010       }
7011       if ((a = a->next)) {
7012         id = *((grn_id *)vp);
7013       } else {
7014         break;
7015       }
7016     }
7017     grn_obj_close(ctx, &buf);
7018   }
7019   return rc;
7020 }
7021 
7022 #define INCRDECR(op) \
7023   switch (DB_OBJ(obj)->range) {\
7024   case GRN_DB_INT8 :\
7025     if (s == sizeof(int8_t)) {\
7026       int8_t *vp = (int8_t *)p;\
7027       *vp op *(int8_t *)v;\
7028       rc = GRN_SUCCESS;\
7029     } else {\
7030       rc = GRN_INVALID_ARGUMENT;\
7031     }\
7032     break;\
7033   case GRN_DB_UINT8 :\
7034     if (s == sizeof(uint8_t)) {\
7035       uint8_t *vp = (uint8_t *)p;\
7036       *vp op *(int8_t *)v;\
7037       rc = GRN_SUCCESS;\
7038     } else {\
7039       rc = GRN_INVALID_ARGUMENT;\
7040     }\
7041     break;\
7042   case GRN_DB_INT16 :\
7043     if (s == sizeof(int16_t)) {\
7044       int16_t *vp = (int16_t *)p;\
7045       *vp op *(int16_t *)v;\
7046       rc = GRN_SUCCESS;\
7047     } else {\
7048       rc = GRN_INVALID_ARGUMENT;\
7049     }\
7050     break;\
7051   case GRN_DB_UINT16 :\
7052     if (s == sizeof(uint16_t)) {\
7053       uint16_t *vp = (uint16_t *)p;\
7054       *vp op *(int16_t *)v;\
7055       rc = GRN_SUCCESS;\
7056     } else {\
7057       rc = GRN_INVALID_ARGUMENT;\
7058     }\
7059     break;\
7060   case GRN_DB_INT32 :\
7061     if (s == sizeof(int32_t)) {\
7062       int32_t *vp = (int32_t *)p;\
7063       *vp op *(int32_t *)v;\
7064       rc = GRN_SUCCESS;\
7065     } else {\
7066       rc = GRN_INVALID_ARGUMENT;\
7067     }\
7068     break;\
7069   case GRN_DB_UINT32 :\
7070     if (s == sizeof(uint32_t)) {\
7071       uint32_t *vp = (uint32_t *)p;\
7072       *vp op *(int32_t *)v;\
7073       rc = GRN_SUCCESS;\
7074     } else {\
7075       rc = GRN_INVALID_ARGUMENT;\
7076     }\
7077     break;\
7078   case GRN_DB_INT64 :\
7079   case GRN_DB_TIME :\
7080     if (s == sizeof(int64_t)) {\
7081       int64_t *vp = (int64_t *)p;\
7082       *vp op *(int64_t *)v;\
7083       rc = GRN_SUCCESS;\
7084     } else {\
7085       rc = GRN_INVALID_ARGUMENT;\
7086     }\
7087     break;\
7088   case GRN_DB_FLOAT :\
7089     if (s == sizeof(double)) {\
7090       double *vp = (double *)p;\
7091       *vp op *(double *)v;\
7092       rc = GRN_SUCCESS;\
7093     } else {\
7094       rc = GRN_INVALID_ARGUMENT;\
7095     }\
7096     break;\
7097   default :\
7098     rc = GRN_OPERATION_NOT_SUPPORTED;\
7099     break;\
7100   }
7101 
7102 uint32_t
grn_obj_size(grn_ctx * ctx,grn_obj * obj)7103 grn_obj_size(grn_ctx *ctx, grn_obj *obj)
7104 {
7105   if (!obj) { return 0; }
7106   switch (obj->header.type) {
7107   case GRN_VOID :
7108   case GRN_BULK :
7109   case GRN_PTR :
7110   case GRN_UVECTOR :
7111   case GRN_PVECTOR :
7112   case GRN_MSG :
7113     return GRN_BULK_VSIZE(obj);
7114   case GRN_VECTOR :
7115     return obj->u.v.body ? GRN_BULK_VSIZE(obj->u.v.body) : 0;
7116   default :
7117     return 0;
7118   }
7119 }
7120 
7121 inline static int
call_hook(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7122 call_hook(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value, int flags)
7123 {
7124   grn_hook *hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET];
7125   void *v = GRN_BULK_HEAD(value);
7126   unsigned int s = grn_obj_size(ctx, value);
7127   if (hooks || obj->header.type == GRN_COLUMN_VAR_SIZE) {
7128     grn_obj oldbuf, *oldvalue;
7129     GRN_TEXT_INIT(&oldbuf, 0);
7130     oldvalue = grn_obj_get_value(ctx, obj, id, &oldbuf);
7131     if (flags & GRN_OBJ_SET) {
7132       void *ov;
7133       unsigned int os;
7134       ov = GRN_BULK_HEAD(oldvalue);
7135       os = grn_obj_size(ctx, oldvalue);
7136       if ((ov && v && os == s && !memcmp(ov, v, s)) &&
7137           !(obj->header.type == GRN_COLUMN_FIX_SIZE &&
7138             grn_bulk_is_zero(ctx, value))) {
7139         grn_obj_close(ctx, oldvalue);
7140         return 0;
7141       }
7142     }
7143     if (hooks) {
7144       // todo : grn_proc_ctx_open()
7145       grn_obj id_, flags_;
7146       grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
7147       GRN_UINT32_INIT(&id_, 0);
7148       GRN_UINT32_INIT(&flags_, 0);
7149       GRN_UINT32_SET(ctx, &id_, id);
7150       GRN_UINT32_SET(ctx, &flags_, flags);
7151       while (hooks) {
7152         grn_ctx_push(ctx, &id_);
7153         grn_ctx_push(ctx, oldvalue);
7154         grn_ctx_push(ctx, value);
7155         grn_ctx_push(ctx, &flags_);
7156         pctx.caller = NULL;
7157         pctx.currh = hooks;
7158         if (hooks->proc) {
7159           hooks->proc->funcs[PROC_INIT](ctx, 1, &obj, &pctx.user_data);
7160         } else {
7161           grn_obj_default_set_value_hook(ctx, 1, &obj, &pctx.user_data);
7162         }
7163         if (ctx->rc) {
7164           grn_obj_close(ctx, oldvalue);
7165           return 1;
7166         }
7167         hooks = hooks->next;
7168         pctx.offset++;
7169       }
7170     }
7171     grn_obj_close(ctx, oldvalue);
7172   }
7173   return 0;
7174 }
7175 
7176 static grn_rc
grn_obj_set_value_table_pat_key(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7177 grn_obj_set_value_table_pat_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
7178                                 grn_obj *value, int flags)
7179 {
7180   grn_rc rc = GRN_INVALID_ARGUMENT;
7181   grn_id range = DB_OBJ(obj)->range;
7182   void *v = GRN_BULK_HEAD(value);
7183   grn_obj buf;
7184 
7185   if (call_hook(ctx, obj, id, value, flags)) {
7186     if (ctx->rc) {
7187       rc = ctx->rc;
7188     }
7189     return rc;
7190   }
7191 
7192   if (range != value->header.domain) {
7193     GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7194     if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7195       v = GRN_BULK_HEAD(&buf);
7196     }
7197   }
7198   rc = grn_pat_set_value(ctx, (grn_pat *)obj, id, v, flags);
7199   if (range != value->header.domain) {
7200     grn_obj_close(ctx, &buf);
7201   }
7202 
7203   return rc;
7204 }
7205 
7206 static grn_rc
grn_obj_set_value_table_hash_key(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7207 grn_obj_set_value_table_hash_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
7208                                  grn_obj *value, int flags)
7209 {
7210   grn_rc rc = GRN_INVALID_ARGUMENT;
7211   grn_id range = DB_OBJ(obj)->range;
7212   void *v = GRN_BULK_HEAD(value);
7213   grn_obj buf;
7214 
7215   if (call_hook(ctx, obj, id, value, flags)) {
7216     if (ctx->rc) {
7217       rc = ctx->rc;
7218     }
7219     return rc;
7220   }
7221 
7222   if (range != value->header.domain) {
7223     GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7224     if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7225       v = GRN_BULK_HEAD(&buf);
7226     }
7227   }
7228   rc = grn_hash_set_value(ctx, (grn_hash *)obj, id, v, flags);
7229   if (range != value->header.domain) {
7230     grn_obj_close(ctx, &buf);
7231   }
7232 
7233   return rc;
7234 }
7235 
7236 static grn_rc
grn_obj_set_value_table_no_key(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7237 grn_obj_set_value_table_no_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
7238                                grn_obj *value, int flags)
7239 {
7240   grn_rc rc = GRN_INVALID_ARGUMENT;
7241   grn_id range = DB_OBJ(obj)->range;
7242   void *v = GRN_BULK_HEAD(value);
7243   grn_obj buf;
7244 
7245   if (call_hook(ctx, obj, id, value, flags)) {
7246     if (ctx->rc) {
7247       rc = ctx->rc;
7248     }
7249     return rc;
7250   }
7251 
7252   if (range != value->header.domain) {
7253     GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7254     if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7255       v = GRN_BULK_HEAD(&buf);
7256     }
7257   }
7258   rc = grn_array_set_value(ctx, (grn_array *)obj, id, v, flags);
7259   if (range != value->header.domain) {
7260     grn_obj_close(ctx, &buf);
7261   }
7262 
7263   return rc;
7264 }
7265 
7266 static grn_rc
grn_obj_set_value_column_var_size_scalar(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7267 grn_obj_set_value_column_var_size_scalar(grn_ctx *ctx, grn_obj *obj, grn_id id,
7268                                          grn_obj *value, int flags)
7269 {
7270   grn_rc rc = GRN_INVALID_ARGUMENT;
7271   grn_id range = DB_OBJ(obj)->range;
7272   void *v = GRN_BULK_HEAD(value);
7273   unsigned int s = grn_obj_size(ctx, value);
7274   grn_obj buf;
7275   grn_id buf_domain = GRN_DB_VOID;
7276 
7277   if (call_hook(ctx, obj, id, value, flags)) {
7278     if (ctx->rc) {
7279       rc = ctx->rc;
7280     }
7281     return rc;
7282   }
7283 
7284   switch (flags & GRN_OBJ_SET_MASK) {
7285   case GRN_OBJ_INCR :
7286   case GRN_OBJ_DECR :
7287     if (value->header.domain == GRN_DB_INT32 ||
7288         value->header.domain == GRN_DB_INT64) {
7289       /* do nothing */
7290     } else if (GRN_DB_INT8 <= value->header.domain &&
7291                value->header.domain < GRN_DB_INT32) {
7292       buf_domain = GRN_DB_INT32;
7293     } else {
7294       buf_domain = GRN_DB_INT64;
7295     }
7296     break;
7297   default :
7298     if (range != value->header.domain) {
7299       buf_domain = range;
7300     }
7301     break;
7302   }
7303 
7304   if (buf_domain != GRN_DB_VOID) {
7305     GRN_OBJ_INIT(&buf, GRN_BULK, 0, buf_domain);
7306     if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7307       v = GRN_BULK_HEAD(&buf);
7308       s = GRN_BULK_VSIZE(&buf);
7309     }
7310   }
7311 
7312   rc = grn_ja_put(ctx, (grn_ja *)obj, id, v, s, flags, NULL);
7313 
7314   if (buf_domain != GRN_DB_VOID) {
7315     grn_obj_close(ctx, &buf);
7316   }
7317 
7318   return rc;
7319 }
7320 
7321 static grn_rc
grn_obj_set_value_column_var_size_vector_uvector(grn_ctx * ctx,grn_obj * column,grn_id id,grn_obj * value,int flags)7322 grn_obj_set_value_column_var_size_vector_uvector(grn_ctx *ctx, grn_obj *column,
7323                                                  grn_id id, grn_obj *value,
7324                                                  int flags)
7325 {
7326   grn_rc rc = GRN_SUCCESS;
7327   grn_obj uvector;
7328   grn_obj_flags uvector_flags = 0;
7329   grn_bool need_convert = GRN_FALSE;
7330   grn_bool need_cast = GRN_FALSE;
7331   grn_id column_range_id;
7332   void *raw_value;
7333   unsigned int size;
7334 
7335   if (column->header.flags & GRN_OBJ_WITH_WEIGHT) {
7336     if (!IS_WEIGHT_UVECTOR(value)) {
7337       need_convert = GRN_TRUE;
7338     }
7339   } else {
7340     if (IS_WEIGHT_UVECTOR(value)) {
7341       need_convert = GRN_TRUE;
7342       uvector_flags = GRN_OBJ_WITH_WEIGHT;
7343     }
7344   }
7345   column_range_id = DB_OBJ(column)->range;
7346   if (column_range_id != value->header.domain) {
7347     need_convert = GRN_TRUE;
7348     need_cast = GRN_TRUE;
7349   }
7350 
7351   if (need_convert) {
7352     unsigned int i, n;
7353 
7354     GRN_VALUE_FIX_SIZE_INIT(&uvector, GRN_OBJ_VECTOR, column_range_id);
7355     uvector.header.flags |= uvector_flags;
7356     n = grn_uvector_size(ctx, value);
7357     if (need_cast) {
7358       grn_obj value_record;
7359       grn_obj casted_record;
7360 
7361       GRN_VALUE_FIX_SIZE_INIT(&value_record, 0, value->header.domain);
7362       GRN_VALUE_FIX_SIZE_INIT(&casted_record, 0, column_range_id);
7363       for (i = 0; i < n; i++) {
7364         grn_id id;
7365         grn_id casted_id;
7366         unsigned int weight = 0;
7367 
7368         GRN_BULK_REWIND(&value_record);
7369         GRN_BULK_REWIND(&casted_record);
7370 
7371         id = grn_uvector_get_element(ctx, value, i, NULL);
7372         GRN_RECORD_SET(ctx, &value_record, id);
7373         rc = grn_obj_cast(ctx, &value_record, &casted_record, GRN_TRUE);
7374         if (rc != GRN_SUCCESS) {
7375           char column_name[GRN_TABLE_MAX_KEY_SIZE];
7376           int column_name_size;
7377           grn_obj inspected;
7378           column_name_size = grn_obj_name(ctx,
7379                                           column,
7380                                           column_name,
7381                                           GRN_TABLE_MAX_KEY_SIZE);
7382           GRN_TEXT_INIT(&inspected, 0);
7383           grn_inspect(ctx, &inspected, &value_record);
7384           ERR(rc,
7385               "[column][set-value] failed to cast: <%.*s>: <%.*s>",
7386               column_name_size,
7387               column_name,
7388               (int)GRN_TEXT_LEN(&inspected),
7389               GRN_TEXT_VALUE(&inspected));
7390           GRN_OBJ_FIN(ctx, &inspected);
7391           break;
7392         }
7393         casted_id = GRN_RECORD_VALUE(&casted_record);
7394         grn_uvector_add_element(ctx, &uvector, casted_id, weight);
7395       }
7396 
7397       GRN_OBJ_FIN(ctx, &value_record);
7398       GRN_OBJ_FIN(ctx, &casted_record);
7399     } else {
7400       for (i = 0; i < n; i++) {
7401         grn_id id;
7402         unsigned int weight = 0;
7403         id = grn_uvector_get_element(ctx, value, i, NULL);
7404         grn_uvector_add_element(ctx, &uvector, id, weight);
7405       }
7406     }
7407     raw_value = GRN_BULK_HEAD(&uvector);
7408     size = GRN_BULK_VSIZE(&uvector);
7409   } else {
7410     raw_value = GRN_BULK_HEAD(value);
7411     size = GRN_BULK_VSIZE(value);
7412   }
7413 
7414   if (rc == GRN_SUCCESS) {
7415     rc = grn_ja_put(ctx, (grn_ja *)column, id, raw_value, size, flags, NULL);
7416   }
7417 
7418   if (need_convert) {
7419     GRN_OBJ_FIN(ctx, &uvector);
7420   }
7421 
7422   return rc;
7423 }
7424 
7425 static grn_rc
grn_obj_set_value_column_var_size_vector(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7426 grn_obj_set_value_column_var_size_vector(grn_ctx *ctx, grn_obj *obj, grn_id id,
7427                                          grn_obj *value, int flags)
7428 {
7429   grn_rc rc = GRN_INVALID_ARGUMENT;
7430   grn_id range = DB_OBJ(obj)->range;
7431   void *v = GRN_BULK_HEAD(value);
7432   unsigned int s = grn_obj_size(ctx, value);
7433   grn_obj *lexicon = grn_ctx_at(ctx, range);
7434 
7435   if (call_hook(ctx, obj, id, value, flags)) {
7436     if (ctx->rc) {
7437       rc = ctx->rc;
7438     }
7439     return rc;
7440   }
7441 
7442   if (value->header.type == GRN_UVECTOR) {
7443     rc = grn_obj_set_value_column_var_size_vector_uvector(ctx, obj,
7444                                                           id, value,
7445                                                           flags);
7446     return rc;
7447   }
7448 
7449   if (GRN_OBJ_TABLEP(lexicon)) {
7450     grn_obj uvector;
7451     GRN_RECORD_INIT(&uvector, GRN_OBJ_VECTOR, range);
7452     if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
7453       uvector.header.flags |= GRN_OBJ_WITH_WEIGHT;
7454     }
7455     switch (value->header.type) {
7456     case GRN_BULK :
7457       {
7458         unsigned int token_flags = 0;
7459         grn_token_cursor *token_cursor;
7460         if (v && s &&
7461             (token_cursor = grn_token_cursor_open(ctx, lexicon, v, s,
7462                                                   GRN_TOKEN_ADD, token_flags))) {
7463           while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
7464             grn_id tid = grn_token_cursor_next(ctx, token_cursor);
7465             grn_uvector_add_element(ctx, &uvector, tid, 0);
7466           }
7467           grn_token_cursor_close(ctx, token_cursor);
7468         }
7469         rc = grn_ja_put(ctx, (grn_ja *)obj, id,
7470                         GRN_BULK_HEAD(&uvector), GRN_BULK_VSIZE(&uvector),
7471                         flags, NULL);
7472       }
7473       break;
7474     case GRN_VECTOR :
7475       {
7476         unsigned int n;
7477         n = grn_vector_size(ctx, value);
7478         if (n > 0) {
7479           unsigned int i;
7480           grn_obj value_buf, cast_buf;
7481           GRN_OBJ_INIT(&value_buf, GRN_BULK, 0, GRN_DB_VOID);
7482           GRN_OBJ_INIT(&cast_buf, GRN_BULK, 0, lexicon->header.domain);
7483           for (i = 0; i < n; i++) {
7484             grn_id tid;
7485             const char *element;
7486             unsigned int element_length;
7487             unsigned int weight;
7488             grn_id element_domain;
7489 
7490             element_length = grn_vector_get_element(ctx, value, i,
7491                                                     &element, &weight,
7492                                                     &element_domain);
7493             if (element_domain != lexicon->header.domain) {
7494               GRN_BULK_REWIND(&cast_buf);
7495               GRN_BULK_REWIND(&value_buf);
7496               grn_bulk_write(ctx, &value_buf, element, element_length);
7497               value_buf.header.domain = element_domain;
7498               rc = grn_obj_cast(ctx, &value_buf, &cast_buf, GRN_TRUE);
7499               if (rc) {
7500                 grn_obj *range_obj;
7501                 range_obj = grn_ctx_at(ctx, range);
7502                 ERR_CAST(obj, range_obj, &value_buf);
7503                 grn_obj_unlink(ctx, range_obj);
7504               } else {
7505                 element = GRN_BULK_HEAD(&cast_buf);
7506                 element_length = GRN_BULK_VSIZE(&cast_buf);
7507               }
7508             } else {
7509               rc = GRN_SUCCESS;
7510             }
7511             if (rc) {
7512               continue;
7513             }
7514             tid = grn_table_add(ctx, lexicon, element, element_length, NULL);
7515             grn_uvector_add_element(ctx, &uvector, tid, weight);
7516           }
7517           GRN_OBJ_FIN(ctx, &value_buf);
7518           GRN_OBJ_FIN(ctx, &cast_buf);
7519         }
7520       }
7521       rc = grn_ja_put(ctx, (grn_ja *)obj, id,
7522                       GRN_BULK_HEAD(&uvector), GRN_BULK_VSIZE(&uvector),
7523                       flags, NULL);
7524       break;
7525     default :
7526       ERR(GRN_INVALID_ARGUMENT, "vector, uvector or bulk required");
7527       break;
7528     }
7529     grn_obj_close(ctx, &uvector);
7530   } else {
7531     switch (value->header.type) {
7532     case GRN_BULK :
7533       if (!GRN_BULK_VSIZE(value)) {
7534         rc = grn_ja_put(ctx, (grn_ja *)obj, id, NULL, 0, flags, NULL);
7535       } else {
7536         grn_obj v;
7537         GRN_OBJ_INIT(&v, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, GRN_DB_TEXT);
7538         v.u.v.body = value;
7539         grn_vector_delimit(ctx, &v, 0, GRN_ID_NIL);
7540         rc = grn_ja_putv(ctx, (grn_ja *)obj, id, &v, 0);
7541         grn_obj_close(ctx, &v);
7542       }
7543       break;
7544     case GRN_VECTOR :
7545       rc = grn_ja_putv(ctx, (grn_ja *)obj, id, value, 0);
7546       break;
7547     default :
7548       ERR(GRN_INVALID_ARGUMENT, "vector or bulk required");
7549       break;
7550     }
7551   }
7552   return rc;
7553 }
7554 
7555 static grn_rc
grn_obj_set_value_column_fix_size(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7556 grn_obj_set_value_column_fix_size(grn_ctx *ctx, grn_obj *obj, grn_id id,
7557                                   grn_obj *value, int flags)
7558 {
7559   grn_rc rc = GRN_INVALID_ARGUMENT;
7560   grn_id range = DB_OBJ(obj)->range;
7561   void *v = GRN_BULK_HEAD(value);
7562   unsigned int s = grn_obj_size(ctx, value);
7563   grn_obj buf, *value_ = value;
7564   uint32_t element_size = ((grn_ra *)obj)->header->element_size;
7565   GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7566   if (range != value->header.domain) {
7567     rc = grn_obj_cast(ctx, value, &buf, GRN_TRUE);
7568     if (rc) {
7569       grn_obj *range_obj;
7570       range_obj = grn_ctx_at(ctx, range);
7571       ERR_CAST(obj, range_obj, value);
7572       grn_obj_unlink(ctx, range_obj);
7573     } else {
7574       value_ = &buf;
7575       v = GRN_BULK_HEAD(&buf);
7576       s = GRN_BULK_VSIZE(&buf);
7577     }
7578   } else {
7579     rc = GRN_SUCCESS;
7580   }
7581   if (rc) {
7582     /* do nothing because it already has error. */
7583   } else if (element_size < s) {
7584     ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", s);
7585   } else {
7586     void *p = grn_ra_ref(ctx, (grn_ra *)obj, id);
7587     if (!p) {
7588       ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
7589       rc = GRN_NO_MEMORY_AVAILABLE;
7590       return rc;
7591     }
7592     switch (flags & GRN_OBJ_SET_MASK) {
7593     case GRN_OBJ_SET :
7594       if (call_hook(ctx, obj, id, value_, flags)) {
7595         if (ctx->rc) {
7596           rc = ctx->rc;
7597         }
7598         GRN_OBJ_FIN(ctx, &buf);
7599         grn_ra_unref(ctx, (grn_ra *)obj, id);
7600         return rc;
7601       }
7602       if (element_size != s) {
7603         if (!s) {
7604           memset(p, 0, element_size);
7605         } else {
7606           void *b;
7607           if ((b = GRN_CALLOC(element_size))) {
7608             grn_memcpy(b, v, s);
7609             grn_memcpy(p, b, element_size);
7610             GRN_FREE(b);
7611           }
7612         }
7613       } else {
7614         grn_memcpy(p, v, s);
7615       }
7616       rc = GRN_SUCCESS;
7617       break;
7618     case GRN_OBJ_INCR :
7619       /* todo : support hook */
7620       INCRDECR(+=);
7621       break;
7622     case GRN_OBJ_DECR :
7623       /* todo : support hook */
7624       INCRDECR(-=);
7625       break;
7626     default :
7627       rc = GRN_OPERATION_NOT_SUPPORTED;
7628       break;
7629     }
7630     grn_ra_unref(ctx, (grn_ra *)obj, id);
7631   }
7632   GRN_OBJ_FIN(ctx, &buf);
7633   return rc;
7634 }
7635 
7636 static grn_rc
grn_obj_set_value_column_index(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7637 grn_obj_set_value_column_index(grn_ctx *ctx, grn_obj *obj, grn_id id,
7638                                grn_obj *value, int flags)
7639 {
7640   char column_name[GRN_TABLE_MAX_KEY_SIZE];
7641   int column_name_size;
7642   column_name_size = grn_obj_name(ctx, obj, column_name,
7643                                   GRN_TABLE_MAX_KEY_SIZE);
7644   ERR(GRN_INVALID_ARGUMENT,
7645       "can't set value to index column directly: <%.*s>",
7646       column_name_size, column_name);
7647   return ctx->rc;
7648 }
7649 
7650 grn_rc
grn_obj_set_value(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value,int flags)7651 grn_obj_set_value(grn_ctx *ctx, grn_obj *obj, grn_id id,
7652                   grn_obj *value, int flags)
7653 {
7654   grn_rc rc = GRN_INVALID_ARGUMENT;
7655   GRN_API_ENTER;
7656   if (!GRN_DB_OBJP(obj)) {
7657     if (obj->header.type == GRN_ACCESSOR) {
7658       rc = grn_accessor_set_value(ctx, (grn_accessor *)obj, id, value, flags);
7659     } else {
7660       ERR(GRN_INVALID_ARGUMENT, "not db_obj");
7661     }
7662   } else {
7663     switch (obj->header.type) {
7664     case GRN_TABLE_PAT_KEY :
7665       rc = grn_obj_set_value_table_pat_key(ctx, obj, id, value, flags);
7666       break;
7667     case GRN_TABLE_DAT_KEY :
7668       rc = GRN_OPERATION_NOT_SUPPORTED;
7669       break;
7670     case GRN_TABLE_HASH_KEY :
7671       rc = grn_obj_set_value_table_hash_key(ctx, obj, id, value, flags);
7672       break;
7673     case GRN_TABLE_NO_KEY :
7674       rc = grn_obj_set_value_table_no_key(ctx, obj, id, value, flags);
7675       break;
7676     case GRN_COLUMN_VAR_SIZE :
7677       switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
7678       case GRN_OBJ_COLUMN_SCALAR :
7679         rc = grn_obj_set_value_column_var_size_scalar(ctx, obj, id, value,
7680                                                       flags);
7681         break;
7682       case GRN_OBJ_COLUMN_VECTOR :
7683         rc = grn_obj_set_value_column_var_size_vector(ctx, obj, id, value,
7684                                                       flags);
7685         break;
7686       default :
7687         ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
7688         break;
7689       }
7690       break;
7691     case GRN_COLUMN_FIX_SIZE :
7692       rc = grn_obj_set_value_column_fix_size(ctx, obj, id, value, flags);
7693       break;
7694     case GRN_COLUMN_INDEX :
7695       rc = grn_obj_set_value_column_index(ctx, obj, id, value, flags);
7696       break;
7697     }
7698   }
7699   GRN_API_RETURN(rc);
7700 }
7701 
7702 const char *
grn_obj_get_value_(grn_ctx * ctx,grn_obj * obj,grn_id id,uint32_t * size)7703 grn_obj_get_value_(grn_ctx *ctx, grn_obj *obj, grn_id id, uint32_t *size)
7704 {
7705   const char *value = NULL;
7706   *size = 0;
7707   switch (obj->header.type) {
7708   case GRN_ACCESSOR :
7709     value = grn_accessor_get_value_(ctx, (grn_accessor *)obj, id, size);
7710     break;
7711   case GRN_TABLE_PAT_KEY :
7712     value = grn_pat_get_value_(ctx, (grn_pat *)obj, id, size);
7713     break;
7714   case GRN_TABLE_DAT_KEY :
7715     ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
7716     break;
7717   case GRN_TABLE_HASH_KEY :
7718     value = grn_hash_get_value_(ctx, (grn_hash *)obj, id, size);
7719     break;
7720   case GRN_TABLE_NO_KEY :
7721     if ((value = _grn_array_get_value(ctx, (grn_array *)obj, id))) {
7722       *size = ((grn_array *)obj)->value_size;
7723     }
7724     break;
7725   case GRN_COLUMN_VAR_SIZE :
7726     {
7727       grn_io_win jw;
7728       if ((value = grn_ja_ref(ctx, (grn_ja *)obj, id, &jw, size))) {
7729         grn_ja_unref(ctx, &jw);
7730       }
7731     }
7732     break;
7733   case GRN_COLUMN_FIX_SIZE :
7734     if ((value = grn_ra_ref(ctx, (grn_ra *)obj, id))) {
7735       grn_ra_unref(ctx, (grn_ra *)obj, id);
7736       *size = ((grn_ra *)obj)->header->element_size;
7737     }
7738     break;
7739   case GRN_COLUMN_INDEX :
7740     ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "todo: GRN_COLUMN_INDEX");
7741     break;
7742   }
7743   return value;
7744 }
7745 
7746 static void
grn_obj_get_value_expr(grn_ctx * ctx,grn_obj * expr,grn_id id,grn_obj * value)7747 grn_obj_get_value_expr(grn_ctx *ctx, grn_obj *expr, grn_id id, grn_obj *value)
7748 {
7749   grn_expr *e = (grn_expr *)expr;
7750   grn_expr_code *code;
7751 
7752   if (e->codes_curr != 1) {
7753     return;
7754   }
7755 
7756   code = e->codes;
7757   if (code->op != GRN_OP_GET_VALUE) {
7758     return;
7759   }
7760 
7761   if (!code->value) {
7762     return;
7763   }
7764 
7765   switch (code->value->header.type) {
7766   case GRN_COLUMN_VAR_SIZE :
7767   case GRN_COLUMN_FIX_SIZE :
7768     grn_obj_get_value(ctx, code->value, id, value);
7769     break;
7770   default :
7771     break;
7772   }
7773 }
7774 
7775 static void
grn_obj_get_value_column_index(grn_ctx * ctx,grn_obj * index_column,grn_id id,grn_obj * value)7776 grn_obj_get_value_column_index(grn_ctx *ctx, grn_obj *index_column,
7777                                grn_id id, grn_obj *value)
7778 {
7779   grn_ii *ii = (grn_ii *)index_column;
7780   grn_obj_ensure_bulk(ctx, value);
7781   if (id) {
7782     GRN_UINT32_SET(ctx, value, grn_ii_estimate_size(ctx, ii, id));
7783   } else {
7784     GRN_UINT32_SET(ctx, value, 0);
7785   }
7786   value->header.domain = GRN_DB_UINT32;
7787 }
7788 
7789 static grn_obj *
grn_obj_get_value_column_vector(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value)7790 grn_obj_get_value_column_vector(grn_ctx *ctx, grn_obj *obj,
7791                                 grn_id id, grn_obj *value)
7792 {
7793   grn_obj *lexicon;
7794 
7795   lexicon = grn_ctx_at(ctx, DB_OBJ(obj)->range);
7796   if (lexicon && !GRN_OBJ_TABLEP(lexicon) &&
7797       (lexicon->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
7798     grn_obj_ensure_vector(ctx, value);
7799     if (id) {
7800       grn_obj v_;
7801       GRN_TEXT_INIT(&v_, 0);
7802       grn_ja_get_value(ctx, (grn_ja *)obj, id, &v_);
7803       grn_vector_decode(ctx, value, GRN_TEXT_VALUE(&v_), GRN_TEXT_LEN(&v_));
7804       GRN_OBJ_FIN(ctx, &v_);
7805     }
7806   } else {
7807     grn_obj_ensure_bulk(ctx, value);
7808     if (id) {
7809       grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
7810     }
7811     value->header.type = GRN_UVECTOR;
7812     if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
7813       value->header.flags |= GRN_OBJ_WITH_WEIGHT;
7814     } else {
7815       value->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
7816     }
7817   }
7818 
7819   return value;
7820 }
7821 
7822 grn_obj *
grn_obj_get_value(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_obj * value)7823 grn_obj_get_value(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value)
7824 {
7825   GRN_API_ENTER;
7826   if (!obj) {
7827     ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
7828     goto exit;
7829   }
7830   if (!value) {
7831     if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
7832       ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
7833       goto exit;
7834     }
7835   }
7836   switch (value->header.type) {
7837   case GRN_VOID :
7838     grn_obj_reinit(ctx, value, GRN_DB_TEXT, 0);
7839     break;
7840   case GRN_BULK :
7841   case GRN_VECTOR :
7842   case GRN_UVECTOR :
7843   case GRN_MSG :
7844     break;
7845   default :
7846     ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
7847     goto exit;
7848   }
7849   switch (obj->header.type) {
7850   case GRN_ACCESSOR :
7851     grn_obj_ensure_bulk(ctx, value);
7852     value = grn_accessor_get_value(ctx, (grn_accessor *)obj, id, value);
7853     break;
7854   case GRN_EXPR :
7855     grn_obj_get_value_expr(ctx, obj, id, value);
7856     break;
7857   case GRN_TABLE_PAT_KEY :
7858     {
7859       grn_pat *pat = (grn_pat *)obj;
7860       uint32_t size = pat->value_size;
7861       grn_obj_ensure_bulk(ctx, value);
7862       if (id) {
7863         if (grn_bulk_space(ctx, value, size)) {
7864           MERR("grn_bulk_space failed");
7865           goto exit;
7866         }
7867         {
7868           char *curr = GRN_BULK_CURR(value);
7869           grn_pat_get_value(ctx, pat, id, curr - size);
7870         }
7871       }
7872       value->header.type = GRN_BULK;
7873       value->header.domain = grn_obj_get_range(ctx, obj);
7874     }
7875     break;
7876   case GRN_TABLE_DAT_KEY :
7877     ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
7878     break;
7879   case GRN_TABLE_HASH_KEY :
7880     {
7881       grn_bool processed = GRN_FALSE;
7882       grn_obj_ensure_bulk(ctx, value);
7883       value->header.domain = grn_obj_get_range(ctx, obj);
7884       if (id) {
7885         if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(obj)) {
7886           grn_obj *domain;
7887           domain = grn_ctx_at(ctx, value->header.domain);
7888           if (GRN_OBJ_TABLEP(domain)) {
7889             grn_id subrec_id;
7890             if (grn_table_get_subrecs(ctx, obj, id, &subrec_id, NULL, 1) == 1) {
7891               GRN_RECORD_SET(ctx, value, subrec_id);
7892               processed = GRN_TRUE;
7893             }
7894           }
7895         }
7896         if (!processed) {
7897           grn_hash *hash = (grn_hash *)obj;
7898           uint32_t size = hash->value_size;
7899           if (grn_bulk_space(ctx, value, size)) {
7900             MERR("grn_bulk_space failed");
7901             goto exit;
7902           }
7903           {
7904             char *curr = GRN_BULK_CURR(value);
7905             grn_hash_get_value(ctx, hash, id, curr - size);
7906           }
7907         }
7908       }
7909     }
7910     break;
7911   case GRN_TABLE_NO_KEY :
7912     {
7913       grn_array *array = (grn_array *)obj;
7914       uint32_t size = array->value_size;
7915       grn_obj_ensure_bulk(ctx, value);
7916       if (id) {
7917         if (grn_bulk_space(ctx, value, size)) {
7918           MERR("grn_bulk_space failed");
7919           goto exit;
7920         }
7921         {
7922           char *curr = GRN_BULK_CURR(value);
7923           grn_array_get_value(ctx, array, id, curr - size);
7924         }
7925       }
7926       value->header.type = GRN_BULK;
7927       value->header.domain = grn_obj_get_range(ctx, obj);
7928     }
7929     break;
7930   case GRN_COLUMN_VAR_SIZE :
7931     switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
7932     case GRN_OBJ_COLUMN_VECTOR :
7933       grn_obj_get_value_column_vector(ctx, obj, id, value);
7934       break;
7935     case GRN_OBJ_COLUMN_SCALAR :
7936       grn_obj_ensure_bulk(ctx, value);
7937       if (id) {
7938         grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
7939       }
7940       value->header.type = GRN_BULK;
7941       break;
7942     default :
7943       ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
7944       break;
7945     }
7946     value->header.domain = grn_obj_get_range(ctx, obj);
7947     break;
7948   case GRN_COLUMN_FIX_SIZE :
7949     grn_obj_ensure_bulk(ctx, value);
7950     value->header.type = GRN_BULK;
7951     value->header.domain = grn_obj_get_range(ctx, obj);
7952     if (id) {
7953       unsigned int element_size;
7954       void *v = grn_ra_ref(ctx, (grn_ra *)obj, id);
7955       if (v) {
7956         element_size = ((grn_ra *)obj)->header->element_size;
7957         grn_bulk_write(ctx, value, v, element_size);
7958         grn_ra_unref(ctx, (grn_ra *)obj, id);
7959       }
7960     }
7961     break;
7962   case GRN_COLUMN_INDEX :
7963     grn_obj_get_value_column_index(ctx, obj, id, value);
7964     break;
7965   }
7966 exit :
7967   GRN_API_RETURN(value);
7968 }
7969 
7970 int
grn_obj_get_values(grn_ctx * ctx,grn_obj * obj,grn_id offset,void ** values)7971 grn_obj_get_values(grn_ctx *ctx, grn_obj *obj, grn_id offset, void **values)
7972 {
7973   int nrecords = -1;
7974   GRN_API_ENTER;
7975   if (obj->header.type == GRN_COLUMN_FIX_SIZE) {
7976     grn_obj *domain = grn_column_table(ctx, obj);
7977     if (domain) {
7978       int table_size = (int)grn_table_size(ctx, domain);
7979       if (0 < offset && offset <= table_size) {
7980         grn_ra *ra = (grn_ra *)obj;
7981         void *p = grn_ra_ref(ctx, ra, offset);
7982         if (p) {
7983           if ((offset >> ra->element_width) == (table_size >> ra->element_width)) {
7984             nrecords = (table_size & ra->element_mask) + 1 - (offset & ra->element_mask);
7985           } else {
7986             nrecords = ra->element_mask + 1 - (offset & ra->element_mask);
7987           }
7988           if (values) { *values = p; }
7989           grn_ra_unref(ctx, ra, offset);
7990         } else {
7991           ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
7992         }
7993       } else {
7994         nrecords = 0;
7995       }
7996     } else {
7997       ERR(GRN_INVALID_ARGUMENT, "no domain found");
7998     }
7999   } else {
8000     ERR(GRN_INVALID_ARGUMENT, "obj is not a fix sized column");
8001   }
8002   GRN_API_RETURN(nrecords);
8003 }
8004 
8005 grn_rc
grn_column_index_update(grn_ctx * ctx,grn_obj * column,grn_id id,unsigned int section,grn_obj * oldvalue,grn_obj * newvalue)8006 grn_column_index_update(grn_ctx *ctx, grn_obj *column,
8007                         grn_id id, unsigned int section,
8008                         grn_obj *oldvalue, grn_obj *newvalue)
8009 {
8010   grn_rc rc = GRN_INVALID_ARGUMENT;
8011   GRN_API_ENTER;
8012   if (column->header.type != GRN_COLUMN_INDEX) {
8013     ERR(GRN_INVALID_ARGUMENT, "invalid column assigned");
8014   } else {
8015     rc = grn_ii_column_update(ctx, (grn_ii *)column, id, section, oldvalue, newvalue, NULL);
8016   }
8017   GRN_API_RETURN(rc);
8018 }
8019 
8020 grn_obj *
grn_column_table(grn_ctx * ctx,grn_obj * column)8021 grn_column_table(grn_ctx *ctx, grn_obj *column)
8022 {
8023   grn_obj *obj = NULL;
8024   grn_db_obj *col = DB_OBJ(column);
8025   GRN_API_ENTER;
8026   if (col) {
8027     obj = grn_ctx_at(ctx, col->header.domain);
8028   }
8029   GRN_API_RETURN(obj);
8030 }
8031 
8032 grn_obj *
grn_obj_get_info(grn_ctx * ctx,grn_obj * obj,grn_info_type type,grn_obj * valuebuf)8033 grn_obj_get_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *valuebuf)
8034 {
8035   GRN_API_ENTER;
8036   switch (type) {
8037   case GRN_INFO_SUPPORT_ZLIB :
8038     if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8039       ERR(GRN_INVALID_ARGUMENT,
8040           "failed to open value buffer for GRN_INFO_ZLIB_SUPPORT");
8041       goto exit;
8042     }
8043 #ifdef GRN_WITH_ZLIB
8044     GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8045 #else
8046     GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8047 #endif
8048     break;
8049   case GRN_INFO_SUPPORT_LZ4 :
8050     if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8051       ERR(GRN_INVALID_ARGUMENT,
8052           "failed to open value buffer for GRN_INFO_LZ4_SUPPORT");
8053       goto exit;
8054     }
8055 #ifdef GRN_WITH_LZ4
8056     GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8057 #else /* GRN_WITH_LZ4 */
8058     GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8059 #endif /* GRN_WITH_LZ4 */
8060     break;
8061   case GRN_INFO_SUPPORT_ZSTD :
8062     if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8063       ERR(GRN_INVALID_ARGUMENT,
8064           "failed to open value buffer for GRN_INFO_ZSTD_SUPPORT");
8065       goto exit;
8066     }
8067 #ifdef GRN_WITH_ZSTD
8068     GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8069 #else /* GRN_WITH_ZSTD */
8070     GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8071 #endif /* GRN_WITH_ZSTD */
8072     break;
8073   case GRN_INFO_SUPPORT_ARROW :
8074     if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8075       ERR(GRN_INVALID_ARGUMENT,
8076           "failed to open value buffer for GRN_INFO_ARROW_SUPPORT");
8077       goto exit;
8078     }
8079 #ifdef GRN_WITH_ARROW
8080     GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8081 #else /* GRN_WITH_ARROW */
8082     GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8083 #endif /* GRN_WITH_ARROW */
8084     break;
8085   default :
8086     if (!obj) {
8087       ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8088       goto exit;
8089     }
8090     switch (type) {
8091     case GRN_INFO_ENCODING :
8092       if (!valuebuf) {
8093         if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
8094           ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8095           goto exit;
8096         }
8097       }
8098       {
8099         grn_encoding enc;
8100         if (obj->header.type == GRN_DB) { obj = ((grn_db *)obj)->keys; }
8101         switch (obj->header.type) {
8102         case GRN_TABLE_PAT_KEY :
8103           enc = ((grn_pat *)obj)->encoding;
8104           grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
8105           break;
8106         case GRN_TABLE_DAT_KEY :
8107           enc = ((grn_dat *)obj)->encoding;
8108           grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
8109           break;
8110         case GRN_TABLE_HASH_KEY :
8111           enc = ((grn_hash *)obj)->encoding;
8112           grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
8113           break;
8114         default :
8115           ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8116         }
8117       }
8118       break;
8119     case GRN_INFO_SOURCE :
8120       if (!valuebuf) {
8121         if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
8122           ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8123           goto exit;
8124         }
8125       }
8126       if (!GRN_DB_OBJP(obj)) {
8127         ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
8128         goto exit;
8129       }
8130       grn_bulk_write(ctx, valuebuf, DB_OBJ(obj)->source, DB_OBJ(obj)->source_size);
8131       break;
8132     case GRN_INFO_DEFAULT_TOKENIZER :
8133       switch (DB_OBJ(obj)->header.type) {
8134       case GRN_TABLE_HASH_KEY :
8135         valuebuf = ((grn_hash *)obj)->tokenizer;
8136         break;
8137       case GRN_TABLE_PAT_KEY :
8138         valuebuf = ((grn_pat *)obj)->tokenizer;
8139         break;
8140       case GRN_TABLE_DAT_KEY :
8141         valuebuf = ((grn_dat *)obj)->tokenizer;
8142         break;
8143       }
8144       break;
8145     case GRN_INFO_NORMALIZER :
8146       switch (DB_OBJ(obj)->header.type) {
8147       case GRN_TABLE_HASH_KEY :
8148         valuebuf = ((grn_hash *)obj)->normalizer;
8149         break;
8150       case GRN_TABLE_PAT_KEY :
8151         valuebuf = ((grn_pat *)obj)->normalizer;
8152         break;
8153       case GRN_TABLE_DAT_KEY :
8154         valuebuf = ((grn_dat *)obj)->normalizer;
8155         break;
8156       }
8157       break;
8158     case GRN_INFO_TOKEN_FILTERS :
8159       if (!valuebuf) {
8160         if (!(valuebuf = grn_obj_open(ctx, GRN_PVECTOR, 0, 0))) {
8161           ERR(GRN_NO_MEMORY_AVAILABLE,
8162               "grn_obj_get_info: failed to allocate value buffer");
8163           goto exit;
8164         }
8165       }
8166       {
8167         grn_obj *token_filters = NULL;
8168         switch (obj->header.type) {
8169         case GRN_TABLE_HASH_KEY :
8170           token_filters = &(((grn_hash *)obj)->token_filters);
8171           break;
8172         case GRN_TABLE_PAT_KEY :
8173           token_filters = &(((grn_pat *)obj)->token_filters);
8174           break;
8175         case GRN_TABLE_DAT_KEY :
8176           token_filters = &(((grn_dat *)obj)->token_filters);
8177           break;
8178         default :
8179           ERR(GRN_INVALID_ARGUMENT,
8180               /* TODO: Show type name instead of type ID */
8181               "[info][get][token-filters] target object must be one of "
8182               "GRN_TABLE_HASH_KEY, GRN_TABLE_PAT_KEY and GRN_TABLE_DAT_KEY: %d",
8183               obj->header.type);
8184           break;
8185         }
8186         if (token_filters) {
8187           grn_bulk_write(ctx,
8188                          valuebuf,
8189                          GRN_BULK_HEAD(token_filters),
8190                          GRN_BULK_VSIZE(token_filters));
8191         }
8192       }
8193       break;
8194     default :
8195       /* todo */
8196       break;
8197     }
8198   }
8199 exit :
8200   GRN_API_RETURN(valuebuf);
8201 }
8202 
8203 static void
update_source_hook(grn_ctx * ctx,grn_obj * obj)8204 update_source_hook(grn_ctx *ctx, grn_obj *obj)
8205 {
8206   grn_id *s = DB_OBJ(obj)->source;
8207   int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
8208   grn_obj_default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
8209   grn_obj *source, data;
8210   GRN_TEXT_INIT(&data, GRN_OBJ_DO_SHALLOW_COPY);
8211   GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
8212   for (i = 1; i <= n; i++, s++) {
8213     hook_data.section = i;
8214     if ((source = grn_ctx_at(ctx, *s))) {
8215       switch (source->header.type) {
8216       case GRN_TABLE_HASH_KEY :
8217       case GRN_TABLE_PAT_KEY :
8218       case GRN_TABLE_DAT_KEY :
8219         grn_obj_add_hook(ctx, source, GRN_HOOK_INSERT, 0, NULL, &data);
8220         grn_obj_add_hook(ctx, source, GRN_HOOK_DELETE, 0, NULL, &data);
8221         break;
8222       case GRN_COLUMN_FIX_SIZE :
8223       case GRN_COLUMN_VAR_SIZE :
8224       case GRN_COLUMN_INDEX :
8225         grn_obj_add_hook(ctx, source, GRN_HOOK_SET, 0, NULL, &data);
8226         break;
8227       default :
8228         /* invalid target */
8229         break;
8230       }
8231     }
8232   }
8233   grn_obj_close(ctx, &data);
8234 }
8235 
8236 static void
del_hook(grn_ctx * ctx,grn_obj * obj,grn_hook_entry entry,grn_obj * hld)8237 del_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, grn_obj *hld)
8238 {
8239   int i;
8240   void *hld_value = NULL;
8241   uint32_t hld_size = 0;
8242   grn_hook **last;
8243   hld_value = GRN_BULK_HEAD(hld);
8244   hld_size = GRN_BULK_VSIZE(hld);
8245   if (!hld_size) { return; }
8246   for (i = 0, last = &DB_OBJ(obj)->hooks[entry]; *last; i++, last = &(*last)->next) {
8247     if (!memcmp(GRN_NEXT_ADDR(*last), hld_value, hld_size)) {
8248       grn_obj_delete_hook(ctx, obj, entry, i);
8249       return;
8250     }
8251   }
8252 }
8253 
8254 static void
delete_source_hook(grn_ctx * ctx,grn_obj * obj)8255 delete_source_hook(grn_ctx *ctx, grn_obj *obj)
8256 {
8257   grn_id *s = DB_OBJ(obj)->source;
8258   int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
8259   grn_obj_default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
8260   grn_obj *source, data;
8261   GRN_TEXT_INIT(&data, GRN_OBJ_DO_SHALLOW_COPY);
8262   GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
8263   for (i = 1; i <= n; i++, s++) {
8264     hook_data.section = i;
8265 
8266     source = grn_ctx_at(ctx, *s);
8267     if (!source) {
8268       ERRCLR(ctx);
8269       continue;
8270     }
8271 
8272     switch (source->header.type) {
8273     case GRN_TABLE_HASH_KEY :
8274     case GRN_TABLE_PAT_KEY :
8275     case GRN_TABLE_DAT_KEY :
8276       del_hook(ctx, source, GRN_HOOK_INSERT, &data);
8277       del_hook(ctx, source, GRN_HOOK_DELETE, &data);
8278       break;
8279     case GRN_COLUMN_FIX_SIZE :
8280     case GRN_COLUMN_VAR_SIZE :
8281       del_hook(ctx, source, GRN_HOOK_SET, &data);
8282       break;
8283     default :
8284       /* invalid target */
8285       break;
8286     }
8287   }
8288   grn_obj_close(ctx, &data);
8289 }
8290 
8291 #define N_HOOK_ENTRIES 5
8292 
8293 grn_rc
grn_hook_pack(grn_ctx * ctx,grn_db_obj * obj,grn_obj * buf)8294 grn_hook_pack(grn_ctx *ctx, grn_db_obj *obj, grn_obj *buf)
8295 {
8296   grn_rc rc;
8297   grn_hook_entry e;
8298   for (e = 0; e < N_HOOK_ENTRIES; e++) {
8299     grn_hook *hooks;
8300     for (hooks = obj->hooks[e]; hooks; hooks = hooks->next) {
8301       grn_id id = hooks->proc ? hooks->proc->obj.id : 0;
8302       if ((rc = grn_text_benc(ctx, buf, id + 1))) { goto exit; }
8303       if ((rc = grn_text_benc(ctx, buf, hooks->hld_size))) { goto exit; }
8304       if ((rc = grn_bulk_write(ctx, buf, (char *)GRN_NEXT_ADDR(hooks), hooks->hld_size))) { goto exit; }
8305     }
8306     if ((rc = grn_text_benc(ctx, buf, 0))) { goto exit; }
8307   }
8308 exit :
8309   return rc;
8310 }
8311 
8312 static grn_rc
grn_hook_unpack(grn_ctx * ctx,grn_db_obj * obj,const char * buf,uint32_t buf_size)8313 grn_hook_unpack(grn_ctx *ctx, grn_db_obj *obj, const char *buf, uint32_t buf_size)
8314 {
8315   grn_hook_entry e;
8316   const uint8_t *p = (uint8_t *)buf, *pe = p + buf_size;
8317   for (e = 0; e < N_HOOK_ENTRIES; e++) {
8318     grn_hook *new, **last = &obj->hooks[e];
8319     for (;;) {
8320       grn_id id;
8321       uint32_t hld_size;
8322       GRN_B_DEC(id, p);
8323       if (!id--) { break; }
8324       if (p >= pe) { return GRN_FILE_CORRUPT; }
8325       GRN_B_DEC(hld_size, p);
8326       if (p >= pe) { return GRN_FILE_CORRUPT; }
8327       if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
8328         return GRN_NO_MEMORY_AVAILABLE;
8329       }
8330       if (id) {
8331         new->proc = (grn_proc *)grn_ctx_at(ctx, id);
8332         if (!new->proc) {
8333           GRN_FREE(new);
8334           return ctx->rc;
8335         }
8336       } else {
8337         new->proc = NULL;
8338       }
8339       if ((new->hld_size = hld_size)) {
8340         grn_memcpy(GRN_NEXT_ADDR(new), p, hld_size);
8341         p += hld_size;
8342       }
8343       *last = new;
8344       last = &new->next;
8345       if (p >= pe) { return GRN_FILE_CORRUPT; }
8346     }
8347     *last = NULL;
8348   }
8349   return GRN_SUCCESS;
8350 }
8351 
8352 static void
grn_token_filters_pack(grn_ctx * ctx,grn_obj * token_filters,grn_obj * buffer)8353 grn_token_filters_pack(grn_ctx *ctx,
8354                        grn_obj *token_filters,
8355                        grn_obj *buffer)
8356 {
8357   unsigned int i, n_token_filters;
8358 
8359   n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
8360   for (i = 0; i < n_token_filters; i++) {
8361     grn_obj *token_filter = GRN_PTR_VALUE_AT(token_filters, i);
8362     grn_id token_filter_id;
8363 
8364     token_filter_id = grn_obj_id(ctx, token_filter);
8365     GRN_RECORD_PUT(ctx, buffer, token_filter_id);
8366   }
8367 }
8368 
8369 static grn_bool
grn_obj_encoded_spec_equal(grn_ctx * ctx,grn_obj * encoded_spec1,grn_obj * encoded_spec2)8370 grn_obj_encoded_spec_equal(grn_ctx *ctx,
8371                            grn_obj *encoded_spec1,
8372                            grn_obj *encoded_spec2)
8373 {
8374   unsigned int i, n_elements;
8375 
8376   if (encoded_spec1->header.type != GRN_VECTOR) {
8377     return GRN_FALSE;
8378   }
8379 
8380   if (encoded_spec1->header.type != encoded_spec2->header.type) {
8381     return GRN_FALSE;
8382   }
8383 
8384   n_elements = grn_vector_size(ctx, encoded_spec1);
8385   if (grn_vector_size(ctx, encoded_spec2) != n_elements) {
8386     return GRN_FALSE;
8387   }
8388 
8389   for (i = 0; i < n_elements; i++) {
8390     const char *content1;
8391     const char *content2;
8392     unsigned int content_size1;
8393     unsigned int content_size2;
8394     unsigned int weight1;
8395     unsigned int weight2;
8396     grn_id domain1;
8397     grn_id domain2;
8398 
8399     content_size1 = grn_vector_get_element(ctx,
8400                                            encoded_spec1,
8401                                            i,
8402                                            &content1,
8403                                            &weight1,
8404                                            &domain1);
8405     content_size2 = grn_vector_get_element(ctx,
8406                                            encoded_spec2,
8407                                            i,
8408                                            &content2,
8409                                            &weight2,
8410                                            &domain2);
8411     if (content_size1 != content_size2) {
8412       return GRN_FALSE;
8413     }
8414     if (memcmp(content1, content2, content_size1) != 0) {
8415       return GRN_FALSE;
8416     }
8417     if (weight1 != weight2) {
8418       return GRN_FALSE;
8419     }
8420     if (domain1 != domain2) {
8421       return GRN_FALSE;
8422     }
8423   }
8424 
8425   return GRN_TRUE;
8426 }
8427 
8428 void
grn_obj_spec_save(grn_ctx * ctx,grn_db_obj * obj)8429 grn_obj_spec_save(grn_ctx *ctx, grn_db_obj *obj)
8430 {
8431   grn_db *s;
8432   grn_obj v, *b;
8433   grn_obj_spec spec;
8434   grn_bool need_update = GRN_TRUE;
8435 
8436   if (obj->id & GRN_OBJ_TMP_OBJECT) { return; }
8437   if (!ctx->impl || !GRN_DB_OBJP(obj)) { return; }
8438   if (!(s = (grn_db *)ctx->impl->db) || !s->specs) { return; }
8439   if (obj->header.type == GRN_PROC && obj->range == GRN_ID_NIL) {
8440     return;
8441   }
8442   GRN_OBJ_INIT(&v, GRN_VECTOR, 0, GRN_DB_TEXT);
8443   if (!(b = grn_vector_body(ctx, &v))) { return; }
8444   spec.header = obj->header;
8445   spec.range = obj->range;
8446   grn_bulk_write(ctx, b, (void *)&spec, sizeof(grn_obj_spec));
8447   grn_vector_delimit(ctx, &v, 0, 0);
8448   if (obj->header.flags & GRN_OBJ_CUSTOM_NAME) {
8449     GRN_TEXT_PUTS(ctx, b, grn_obj_path(ctx, (grn_obj *)obj));
8450   }
8451   grn_vector_delimit(ctx, &v, 0, 0);
8452   grn_bulk_write(ctx, b, obj->source, obj->source_size);
8453   grn_vector_delimit(ctx, &v, 0, 0);
8454   grn_hook_pack(ctx, obj, b);
8455   grn_vector_delimit(ctx, &v, 0, 0);
8456   switch (obj->header.type) {
8457   case GRN_TABLE_HASH_KEY :
8458     grn_token_filters_pack(ctx, &(((grn_hash *)obj)->token_filters), b);
8459     grn_vector_delimit(ctx, &v, 0, 0);
8460     break;
8461   case GRN_TABLE_PAT_KEY :
8462     grn_token_filters_pack(ctx, &(((grn_pat *)obj)->token_filters), b);
8463     grn_vector_delimit(ctx, &v, 0, 0);
8464     break;
8465   case GRN_TABLE_DAT_KEY :
8466     grn_token_filters_pack(ctx, &(((grn_dat *)obj)->token_filters), b);
8467     grn_vector_delimit(ctx, &v, 0, 0);
8468     break;
8469   case GRN_EXPR :
8470     grn_expr_pack(ctx, b, (grn_obj *)obj);
8471     grn_vector_delimit(ctx, &v, 0, 0);
8472     break;
8473   }
8474 
8475   {
8476     grn_io_win jw;
8477     uint32_t current_spec_raw_len;
8478     char *current_spec_raw;
8479 
8480     current_spec_raw = grn_ja_ref(ctx,
8481                                   s->specs,
8482                                   obj->id,
8483                                   &jw,
8484                                   &current_spec_raw_len);
8485     if (current_spec_raw) {
8486       grn_rc rc;
8487       grn_obj current_spec;
8488 
8489       GRN_OBJ_INIT(&current_spec, GRN_VECTOR, 0, GRN_DB_TEXT);
8490       rc = grn_vector_decode(ctx,
8491                              &current_spec,
8492                              current_spec_raw,
8493                              current_spec_raw_len);
8494       if (rc == GRN_SUCCESS) {
8495         need_update = !grn_obj_encoded_spec_equal(ctx, &v, &current_spec);
8496       }
8497       GRN_OBJ_FIN(ctx, &current_spec);
8498       grn_ja_unref(ctx, &jw);
8499     }
8500   }
8501 
8502   if (!need_update) {
8503     grn_obj_close(ctx, &v);
8504     return;
8505   }
8506 
8507   {
8508     const char *name;
8509     uint32_t name_size = 0;
8510     const char *range_name = NULL;
8511     uint32_t range_name_size = 0;
8512 
8513     name = _grn_table_key(ctx, s->keys, obj->id, &name_size);
8514     switch (obj->header.type) {
8515     case GRN_TABLE_HASH_KEY :
8516     case GRN_TABLE_PAT_KEY :
8517     case GRN_TABLE_DAT_KEY :
8518     case GRN_TABLE_NO_KEY :
8519     case GRN_COLUMN_FIX_SIZE :
8520     case GRN_COLUMN_VAR_SIZE :
8521     case GRN_COLUMN_INDEX :
8522       if (obj->range != GRN_ID_NIL) {
8523         range_name = _grn_table_key(ctx, s->keys, obj->range, &range_name_size);
8524       }
8525       break;
8526     default :
8527       break;
8528     }
8529     /* TODO: reduce log level. */
8530     GRN_LOG(ctx, GRN_LOG_NOTICE,
8531             "spec:%u:update:%.*s:%u(%s):%u%s%.*s%s",
8532             obj->id,
8533             name_size, name,
8534             obj->header.type,
8535             grn_obj_type_to_string(obj->header.type),
8536             obj->range,
8537             range_name_size == 0 ? "" : "(",
8538             range_name_size, range_name,
8539             range_name_size == 0 ? "" : ")");
8540   }
8541   grn_ja_putv(ctx, s->specs, obj->id, &v, 0);
8542   grn_obj_close(ctx, &v);
8543 }
8544 
8545 inline static void
grn_obj_set_info_source_invalid_lexicon_error(grn_ctx * ctx,const char * message,grn_obj * actual_type,grn_obj * expected_type,grn_obj * index_column,grn_obj * source)8546 grn_obj_set_info_source_invalid_lexicon_error(grn_ctx *ctx,
8547                                               const char *message,
8548                                               grn_obj *actual_type,
8549                                               grn_obj *expected_type,
8550                                               grn_obj *index_column,
8551                                               grn_obj *source)
8552 {
8553   char actual_type_name[GRN_TABLE_MAX_KEY_SIZE];
8554   int actual_type_name_size;
8555   char expected_type_name[GRN_TABLE_MAX_KEY_SIZE];
8556   int expected_type_name_size;
8557   char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
8558   int index_column_name_size;
8559   char source_name[GRN_TABLE_MAX_KEY_SIZE];
8560   int source_name_size;
8561 
8562   actual_type_name_size = grn_obj_name(ctx, actual_type,
8563                                        actual_type_name,
8564                                        GRN_TABLE_MAX_KEY_SIZE);
8565   expected_type_name_size = grn_obj_name(ctx, expected_type,
8566                                          expected_type_name,
8567                                          GRN_TABLE_MAX_KEY_SIZE);
8568   index_column_name_size = grn_obj_name(ctx, index_column,
8569                                         index_column_name,
8570                                         GRN_TABLE_MAX_KEY_SIZE);
8571 
8572   source_name_size = grn_obj_name(ctx, source,
8573                                   source_name, GRN_TABLE_MAX_KEY_SIZE);
8574   if (grn_obj_is_table(ctx, source)) {
8575     source_name[source_name_size] = '\0';
8576     grn_strncat(source_name,
8577                 GRN_TABLE_MAX_KEY_SIZE,
8578                 "._key",
8579                 GRN_TABLE_MAX_KEY_SIZE - source_name_size - 1);
8580     source_name_size = strlen(source_name);
8581   }
8582 
8583   ERR(GRN_INVALID_ARGUMENT,
8584       "[column][index][source] %s: "
8585       "<%.*s> -> <%.*s>: "
8586       "index-column:<%.*s> "
8587       "source:<%.*s>",
8588       message,
8589       actual_type_name_size, actual_type_name,
8590       expected_type_name_size, expected_type_name,
8591       index_column_name_size, index_column_name,
8592       source_name_size, source_name);
8593 }
8594 
8595 inline static grn_rc
grn_obj_set_info_source_validate(grn_ctx * ctx,grn_obj * obj,grn_obj * value)8596 grn_obj_set_info_source_validate(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8597 {
8598   grn_id lexicon_id;
8599   grn_obj *lexicon = NULL;
8600   grn_id lexicon_domain_id;
8601   grn_obj *lexicon_domain = NULL;
8602   grn_bool lexicon_domain_is_table;
8603   grn_bool lexicon_have_tokenizer;
8604   grn_id *source_ids;
8605   int i, n_source_ids;
8606 
8607   lexicon_id = obj->header.domain;
8608   lexicon = grn_ctx_at(ctx, lexicon_id);
8609   if (!lexicon) {
8610     goto exit;
8611   }
8612 
8613   lexicon_domain_id = lexicon->header.domain;
8614   lexicon_domain = grn_ctx_at(ctx, lexicon_domain_id);
8615   if (!lexicon_domain) {
8616     goto exit;
8617   }
8618 
8619   source_ids = (grn_id *)GRN_BULK_HEAD(value);
8620   n_source_ids = GRN_BULK_VSIZE(value) / sizeof(grn_id);
8621   if (n_source_ids > 1 && !(obj->header.flags & GRN_OBJ_WITH_SECTION)) {
8622     char index_name[GRN_TABLE_MAX_KEY_SIZE];
8623     int index_name_size;
8624     index_name_size = grn_obj_name(ctx, obj,
8625                                    index_name, GRN_TABLE_MAX_KEY_SIZE);
8626     ERR(GRN_INVALID_ARGUMENT,
8627         "grn_obj_set_info(): GRN_INFO_SOURCE: "
8628         "multi column index must be created with WITH_SECTION flag: <%.*s>",
8629         index_name_size, index_name);
8630     goto exit;
8631   }
8632 
8633   lexicon_domain_is_table = grn_obj_is_table(ctx, lexicon_domain);
8634   {
8635     grn_obj *tokenizer;
8636     grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
8637     lexicon_have_tokenizer = (tokenizer != NULL);
8638   }
8639 
8640   for (i = 0; i < n_source_ids; i++) {
8641     grn_id source_id = source_ids[i];
8642     grn_obj *source;
8643     grn_id source_type_id;
8644     grn_obj *source_type;
8645 
8646     source = grn_ctx_at(ctx, source_id);
8647     if (!source) {
8648       continue;
8649     }
8650     if (grn_obj_is_table(ctx, source)) {
8651       source_type_id = source->header.domain;
8652     } else {
8653       source_type_id = DB_OBJ(source)->range;
8654     }
8655     source_type = grn_ctx_at(ctx, source_type_id);
8656     if (!lexicon_have_tokenizer) {
8657       if (grn_obj_is_table(ctx, source_type)) {
8658         if (lexicon_id != source_type_id) {
8659           grn_obj_set_info_source_invalid_lexicon_error(
8660             ctx,
8661             "index table must equal to source type",
8662             lexicon,
8663             source_type,
8664             obj,
8665             source);
8666         }
8667       } else {
8668         if (!(lexicon_domain_id == source_type_id ||
8669               (grn_type_id_is_text_family(ctx, lexicon_domain_id) &&
8670                grn_type_id_is_text_family(ctx, source_type_id)))) {
8671           grn_obj_set_info_source_invalid_lexicon_error(
8672             ctx,
8673             "index table's key must equal source type",
8674             lexicon_domain,
8675             source_type,
8676             obj,
8677             source);
8678         }
8679       }
8680     }
8681     grn_obj_unlink(ctx, source);
8682     if (ctx->rc != GRN_SUCCESS) {
8683       goto exit;
8684     }
8685   }
8686 
8687 exit:
8688   if (lexicon) {
8689     grn_obj_unlink(ctx, lexicon);
8690   }
8691   if (lexicon_domain) {
8692     grn_obj_unlink(ctx, lexicon_domain);
8693   }
8694   return ctx->rc;
8695 }
8696 
8697 inline static void
grn_obj_set_info_source_log(grn_ctx * ctx,grn_obj * obj,grn_obj * value)8698 grn_obj_set_info_source_log(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8699 {
8700   grn_obj buf;
8701   grn_id *vp = (grn_id *)GRN_BULK_HEAD(value);
8702   uint32_t vs = GRN_BULK_VSIZE(value), s = 0;
8703   grn_id id;
8704   const char *n;
8705 
8706   id = DB_OBJ(obj)->id;
8707   n = _grn_table_key(ctx, ctx->impl->db, id, &s);
8708   GRN_TEXT_INIT(&buf, 0);
8709   GRN_TEXT_PUT(ctx, &buf, n, s);
8710   GRN_TEXT_PUTC(ctx, &buf, ' ');
8711   while (vs) {
8712     n = _grn_table_key(ctx, ctx->impl->db, *vp++, &s);
8713     GRN_TEXT_PUT(ctx, &buf, n, s);
8714     vs -= sizeof(grn_id);
8715     if (vs) { GRN_TEXT_PUTC(ctx, &buf, ','); }
8716   }
8717   GRN_LOG(ctx, GRN_LOG_NOTICE,
8718           "DDL:%u:set_source %.*s",
8719           id,
8720           (int)GRN_BULK_VSIZE(&buf), GRN_BULK_HEAD(&buf));
8721   GRN_OBJ_FIN(ctx, &buf);
8722 }
8723 
8724 inline static grn_rc
grn_obj_set_info_source_update(grn_ctx * ctx,grn_obj * obj,grn_obj * value)8725 grn_obj_set_info_source_update(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8726 {
8727   void *v = GRN_BULK_HEAD(value);
8728   uint32_t s = GRN_BULK_VSIZE(value);
8729   if (s) {
8730     void *v2 = GRN_MALLOC(s);
8731     if (!v2) {
8732       return ctx->rc;
8733     }
8734     grn_memcpy(v2, v, s);
8735     if (DB_OBJ(obj)->source) { GRN_FREE(DB_OBJ(obj)->source); }
8736     DB_OBJ(obj)->source = v2;
8737     DB_OBJ(obj)->source_size = s;
8738 
8739     if (obj->header.type == GRN_COLUMN_INDEX) {
8740       update_source_hook(ctx, obj);
8741       grn_index_column_build(ctx, obj);
8742     }
8743   } else {
8744     DB_OBJ(obj)->source = NULL;
8745     DB_OBJ(obj)->source_size = 0;
8746   }
8747 
8748   return GRN_SUCCESS;
8749 }
8750 
8751 inline static grn_rc
grn_obj_set_info_source(grn_ctx * ctx,grn_obj * obj,grn_obj * value)8752 grn_obj_set_info_source(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8753 {
8754   grn_rc rc;
8755 
8756   rc = grn_obj_set_info_source_validate(ctx, obj, value);
8757   if (rc != GRN_SUCCESS) {
8758     return rc;
8759   }
8760   grn_obj_set_info_source_log(ctx, obj, value);
8761   rc = grn_obj_set_info_source_update(ctx, obj, value);
8762   if (rc != GRN_SUCCESS) {
8763     return rc;
8764   }
8765   grn_obj_spec_save(ctx, DB_OBJ(obj));
8766 
8767   return rc;
8768 }
8769 
8770 static grn_rc
grn_obj_set_info_token_filters(grn_ctx * ctx,grn_obj * table,grn_obj * token_filters)8771 grn_obj_set_info_token_filters(grn_ctx *ctx,
8772                                grn_obj *table,
8773                                grn_obj *token_filters)
8774 {
8775   grn_obj *current_token_filters;
8776   unsigned int i, n_current_token_filters, n_token_filters;
8777   grn_obj token_filter_names;
8778 
8779   switch (table->header.type) {
8780   case GRN_TABLE_HASH_KEY :
8781     current_token_filters = &(((grn_hash *)table)->token_filters);
8782     break;
8783   case GRN_TABLE_PAT_KEY :
8784     current_token_filters = &(((grn_pat *)table)->token_filters);
8785     break;
8786   case GRN_TABLE_DAT_KEY :
8787     current_token_filters = &(((grn_dat *)table)->token_filters);
8788     break;
8789   default :
8790     /* TODO: Show type name instead of type ID */
8791     ERR(GRN_INVALID_ARGUMENT,
8792         "[info][set][token-filters] target object must be one of "
8793         "GRN_TABLE_HASH_KEY, GRN_TABLE_PAT_KEY and GRN_TABLE_DAT_KEY: %d",
8794         table->header.type);
8795     return ctx->rc;
8796   }
8797 
8798   n_current_token_filters =
8799     GRN_BULK_VSIZE(current_token_filters) / sizeof(grn_obj *);
8800   n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
8801 
8802   GRN_TEXT_INIT(&token_filter_names, 0);
8803   GRN_BULK_REWIND(current_token_filters);
8804   for (i = 0; i < n_token_filters; i++) {
8805     grn_obj *token_filter = GRN_PTR_VALUE_AT(token_filters, i);
8806     char token_filter_name[GRN_TABLE_MAX_KEY_SIZE];
8807     unsigned int token_filter_name_size;
8808 
8809     GRN_PTR_PUT(ctx, current_token_filters, token_filter);
8810 
8811     if (i > 0) {
8812       GRN_TEXT_PUTC(ctx, &token_filter_names, ',');
8813     }
8814     token_filter_name_size = grn_obj_name(ctx,
8815                                           token_filter,
8816                                           token_filter_name,
8817                                           GRN_TABLE_MAX_KEY_SIZE);
8818     GRN_TEXT_PUT(ctx,
8819                  &token_filter_names,
8820                  token_filter_name,
8821                  token_filter_name_size);
8822   }
8823   if (n_token_filters > 0 || n_token_filters != n_current_token_filters) {
8824     GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:%u:set_token_filters %.*s",
8825             DB_OBJ(table)->id,
8826             (int)GRN_BULK_VSIZE(&token_filter_names),
8827             GRN_BULK_HEAD(&token_filter_names));
8828   }
8829   GRN_OBJ_FIN(ctx, &token_filter_names);
8830   grn_obj_spec_save(ctx, DB_OBJ(table));
8831 
8832   return GRN_SUCCESS;
8833 }
8834 
8835 grn_rc
grn_obj_set_info(grn_ctx * ctx,grn_obj * obj,grn_info_type type,grn_obj * value)8836 grn_obj_set_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *value)
8837 {
8838   grn_rc rc = GRN_INVALID_ARGUMENT;
8839   GRN_API_ENTER;
8840   if (!obj) {
8841     ERR(GRN_INVALID_ARGUMENT, "grn_obj_set_info failed");
8842     goto exit;
8843   }
8844   switch (type) {
8845   case GRN_INFO_SOURCE :
8846     if (!GRN_DB_OBJP(obj)) {
8847       ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
8848       goto exit;
8849     }
8850     rc = grn_obj_set_info_source(ctx, obj, value);
8851     break;
8852   case GRN_INFO_DEFAULT_TOKENIZER :
8853     if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
8854       switch (DB_OBJ(obj)->header.type) {
8855       case GRN_TABLE_HASH_KEY :
8856         ((grn_hash *)obj)->tokenizer = value;
8857         ((grn_hash *)obj)->header.common->tokenizer = grn_obj_id(ctx, value);
8858         rc = GRN_SUCCESS;
8859         break;
8860       case GRN_TABLE_PAT_KEY :
8861         ((grn_pat *)obj)->tokenizer = value;
8862         ((grn_pat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
8863         rc = GRN_SUCCESS;
8864         break;
8865       case GRN_TABLE_DAT_KEY :
8866         ((grn_dat *)obj)->tokenizer = value;
8867         ((grn_dat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
8868         rc = GRN_SUCCESS;
8869         break;
8870       }
8871     }
8872     break;
8873   case GRN_INFO_NORMALIZER :
8874     if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
8875       switch (DB_OBJ(obj)->header.type) {
8876       case GRN_TABLE_HASH_KEY :
8877         ((grn_hash *)obj)->normalizer = value;
8878         ((grn_hash *)obj)->header.common->normalizer = grn_obj_id(ctx, value);
8879         rc = GRN_SUCCESS;
8880         break;
8881       case GRN_TABLE_PAT_KEY :
8882         ((grn_pat *)obj)->normalizer = value;
8883         ((grn_pat *)obj)->header->normalizer = grn_obj_id(ctx, value);
8884         rc = GRN_SUCCESS;
8885         break;
8886       case GRN_TABLE_DAT_KEY :
8887         ((grn_dat *)obj)->normalizer = value;
8888         ((grn_dat *)obj)->header->normalizer = grn_obj_id(ctx, value);
8889         rc = GRN_SUCCESS;
8890         break;
8891       }
8892     }
8893     break;
8894   case GRN_INFO_TOKEN_FILTERS :
8895     rc = grn_obj_set_info_token_filters(ctx, obj, value);
8896     break;
8897   default :
8898     /* todo */
8899     break;
8900   }
8901 exit :
8902   GRN_API_RETURN(rc);
8903 }
8904 
8905 grn_obj *
grn_obj_get_element_info(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_info_type type,grn_obj * valuebuf)8906 grn_obj_get_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
8907                          grn_info_type type, grn_obj *valuebuf)
8908 {
8909   GRN_API_ENTER;
8910   GRN_API_RETURN(valuebuf);
8911 }
8912 
8913 grn_rc
grn_obj_set_element_info(grn_ctx * ctx,grn_obj * obj,grn_id id,grn_info_type type,grn_obj * value)8914 grn_obj_set_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
8915                          grn_info_type type, grn_obj *value)
8916 {
8917   GRN_API_ENTER;
8918   GRN_API_RETURN(GRN_SUCCESS);
8919 }
8920 
8921 static void
grn_hook_free(grn_ctx * ctx,grn_hook * h)8922 grn_hook_free(grn_ctx *ctx, grn_hook *h)
8923 {
8924   grn_hook *curr, *next;
8925   for (curr = h; curr; curr = next) {
8926     next = curr->next;
8927     GRN_FREE(curr);
8928   }
8929 }
8930 
8931 grn_rc
grn_obj_add_hook(grn_ctx * ctx,grn_obj * obj,grn_hook_entry entry,int offset,grn_obj * proc,grn_obj * hld)8932 grn_obj_add_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
8933                  int offset, grn_obj *proc, grn_obj *hld)
8934 {
8935   grn_rc rc = GRN_SUCCESS;
8936   GRN_API_ENTER;
8937   if (!GRN_DB_OBJP(obj)) {
8938     rc = GRN_INVALID_ARGUMENT;
8939   } else {
8940     int i;
8941     void *hld_value = NULL;
8942     uint32_t hld_size = 0;
8943     grn_hook *new, **last = &DB_OBJ(obj)->hooks[entry];
8944     if (hld) {
8945       hld_value = GRN_BULK_HEAD(hld);
8946       hld_size = GRN_BULK_VSIZE(hld);
8947     }
8948     if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
8949       rc = GRN_NO_MEMORY_AVAILABLE;
8950       goto exit;
8951     }
8952     new->proc = (grn_proc *)proc;
8953     new->hld_size = hld_size;
8954     if (hld_size) {
8955       grn_memcpy(GRN_NEXT_ADDR(new), hld_value, hld_size);
8956     }
8957     for (i = 0; i != offset && *last; i++) { last = &(*last)->next; }
8958     new->next = *last;
8959     *last = new;
8960     grn_obj_spec_save(ctx, DB_OBJ(obj));
8961   }
8962 exit :
8963   GRN_API_RETURN(rc);
8964 }
8965 
8966 int
grn_obj_get_nhooks(grn_ctx * ctx,grn_obj * obj,grn_hook_entry entry)8967 grn_obj_get_nhooks(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry)
8968 {
8969   int res = 0;
8970   GRN_API_ENTER;
8971   {
8972     grn_hook *hook = DB_OBJ(obj)->hooks[entry];
8973     while (hook) {
8974       res++;
8975       hook = hook->next;
8976     }
8977   }
8978   GRN_API_RETURN(res);
8979 }
8980 
8981 grn_obj *
grn_obj_get_hook(grn_ctx * ctx,grn_obj * obj,grn_hook_entry entry,int offset,grn_obj * hldbuf)8982 grn_obj_get_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
8983                       int offset, grn_obj *hldbuf)
8984 {
8985   grn_obj *res = NULL;
8986   GRN_API_ENTER;
8987   {
8988     int i;
8989     grn_hook *hook = DB_OBJ(obj)->hooks[entry];
8990     for (i = 0; i < offset; i++) {
8991       hook = hook->next;
8992       if (!hook) { return NULL; }
8993     }
8994     res = (grn_obj *)hook->proc;
8995     grn_bulk_write(ctx, hldbuf, (char *)GRN_NEXT_ADDR(hook), hook->hld_size);
8996   }
8997   GRN_API_RETURN(res);
8998 }
8999 
9000 grn_rc
grn_obj_delete_hook(grn_ctx * ctx,grn_obj * obj,grn_hook_entry entry,int offset)9001 grn_obj_delete_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, int offset)
9002 {
9003   GRN_API_ENTER;
9004   {
9005     int i = 0;
9006     grn_hook *h, **last = &DB_OBJ(obj)->hooks[entry];
9007     for (;;) {
9008       if (!(h = *last)) { return GRN_INVALID_ARGUMENT; }
9009       if (++i > offset) { break; }
9010       last = &h->next;
9011     }
9012     *last = h->next;
9013     GRN_FREE(h);
9014   }
9015   grn_obj_spec_save(ctx, DB_OBJ(obj));
9016   GRN_API_RETURN(GRN_SUCCESS);
9017 }
9018 
9019 static grn_rc
remove_index(grn_ctx * ctx,grn_obj * obj,grn_hook_entry entry)9020 remove_index(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry)
9021 {
9022   grn_rc rc = GRN_SUCCESS;
9023   grn_hook *h0, *hooks = DB_OBJ(obj)->hooks[entry];
9024   DB_OBJ(obj)->hooks[entry] = NULL; /* avoid mutual recursive call */
9025   while (hooks) {
9026     grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
9027     grn_obj *target = grn_ctx_at(ctx, data->target);
9028     if (!target) {
9029       char name[GRN_TABLE_MAX_KEY_SIZE];
9030       int length;
9031       char hook_name[GRN_TABLE_MAX_KEY_SIZE];
9032       int hook_name_length;
9033 
9034       length = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
9035       hook_name_length = grn_table_get_key(ctx,
9036                                            ctx->impl->db,
9037                                            data->target,
9038                                            hook_name,
9039                                            GRN_TABLE_MAX_KEY_SIZE);
9040       ERR(GRN_OBJECT_CORRUPT,
9041           "[column][remove][index] "
9042           "hook has a dangling reference: <%.*s> -> <%.*s>",
9043           length, name,
9044           hook_name_length, hook_name);
9045       rc = ctx->rc;
9046     } else if (target->header.type == GRN_COLUMN_INDEX) {
9047       //TODO: multicolumn  MULTI_COLUMN_INDEXP
9048       rc = _grn_obj_remove(ctx, target, GRN_FALSE);
9049     } else {
9050       //TODO: err
9051       char fn[GRN_TABLE_MAX_KEY_SIZE];
9052       int flen;
9053       flen = grn_obj_name(ctx, target, fn, GRN_TABLE_MAX_KEY_SIZE);
9054       fn[flen] = '\0';
9055       ERR(GRN_UNKNOWN_ERROR, "column has unsupported hooks, col=%s",fn);
9056       rc = ctx->rc;
9057     }
9058     if (rc != GRN_SUCCESS) {
9059       DB_OBJ(obj)->hooks[entry] = hooks;
9060       break;
9061     }
9062     h0 = hooks;
9063     hooks = hooks->next;
9064     GRN_FREE(h0);
9065   }
9066   return rc;
9067 }
9068 
9069 static grn_rc
remove_columns(grn_ctx * ctx,grn_obj * obj)9070 remove_columns(grn_ctx *ctx, grn_obj *obj)
9071 {
9072   grn_rc rc = GRN_SUCCESS;
9073   grn_hash *cols;
9074   if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
9075                               GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
9076     if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
9077       GRN_HASH_EACH_BEGIN(ctx, cols, cursor, id) {
9078         grn_id *key;
9079         grn_obj *col;
9080 
9081         grn_hash_cursor_get_key(ctx, cursor, (void **)&key);
9082         col = grn_ctx_at(ctx, *key);
9083 
9084         if (!col) {
9085           char name[GRN_TABLE_MAX_KEY_SIZE];
9086           int name_size;
9087           name_size = grn_table_get_key(ctx, ctx->impl->db, *key,
9088                                         name, GRN_TABLE_MAX_KEY_SIZE);
9089           if (ctx->rc == GRN_SUCCESS) {
9090             ERR(GRN_INVALID_ARGUMENT,
9091                 "[object][remove] column is broken: <%.*s>",
9092                 name_size, name);
9093           } else {
9094             ERR(ctx->rc,
9095                 "[object][remove] column is broken: <%.*s>: %s",
9096                 name_size, name,
9097                 ctx->errbuf);
9098           }
9099           rc = ctx->rc;
9100           break;
9101         }
9102 
9103         rc = _grn_obj_remove(ctx, col, GRN_FALSE);
9104         if (rc != GRN_SUCCESS) {
9105           grn_obj_unlink(ctx, col);
9106           break;
9107         }
9108       } GRN_HASH_EACH_END(ctx, cursor);
9109     }
9110     grn_hash_close(ctx, cols);
9111   }
9112   return rc;
9113 }
9114 
9115 static grn_rc
_grn_obj_remove_db_index_columns(grn_ctx * ctx,grn_obj * db)9116 _grn_obj_remove_db_index_columns(grn_ctx *ctx, grn_obj *db)
9117 {
9118   grn_rc rc = GRN_SUCCESS;
9119   grn_table_cursor *cur;
9120   if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9121     grn_id id;
9122     while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9123       grn_obj *obj = grn_ctx_at(ctx, id);
9124       if (obj && obj->header.type == GRN_COLUMN_INDEX) {
9125         rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9126         if (rc != GRN_SUCCESS) {
9127           grn_obj_unlink(ctx, obj);
9128           break;
9129         }
9130       }
9131     }
9132     grn_table_cursor_close(ctx, cur);
9133   }
9134   return rc;
9135 }
9136 
9137 static grn_rc
_grn_obj_remove_db_reference_columns(grn_ctx * ctx,grn_obj * db)9138 _grn_obj_remove_db_reference_columns(grn_ctx *ctx, grn_obj *db)
9139 {
9140   grn_rc rc = GRN_SUCCESS;
9141   grn_table_cursor *cur;
9142   if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9143     grn_id id;
9144     while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9145       grn_obj *obj = grn_ctx_at(ctx, id);
9146       grn_obj *range = NULL;
9147 
9148       if (!obj) {
9149         continue;
9150       }
9151 
9152       switch (obj->header.type) {
9153       case GRN_COLUMN_FIX_SIZE :
9154       case GRN_COLUMN_VAR_SIZE :
9155         if (!DB_OBJ(obj)->range) {
9156           break;
9157         }
9158 
9159         range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
9160         if (!range) {
9161           break;
9162         }
9163 
9164         switch (range->header.type) {
9165         case GRN_TABLE_NO_KEY :
9166         case GRN_TABLE_HASH_KEY :
9167         case GRN_TABLE_PAT_KEY :
9168         case GRN_TABLE_DAT_KEY :
9169           rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9170           break;
9171         }
9172         break;
9173       }
9174 
9175       if (rc != GRN_SUCCESS) {
9176         break;
9177       }
9178     }
9179     grn_table_cursor_close(ctx, cur);
9180   }
9181   return rc;
9182 }
9183 
9184 static grn_rc
_grn_obj_remove_db_reference_tables(grn_ctx * ctx,grn_obj * db)9185 _grn_obj_remove_db_reference_tables(grn_ctx *ctx, grn_obj *db)
9186 {
9187   grn_rc rc = GRN_SUCCESS;
9188   grn_table_cursor *cur;
9189   if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9190     grn_id id;
9191     while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9192       grn_obj *obj = grn_ctx_at(ctx, id);
9193       grn_obj *domain = NULL;
9194 
9195       if (!obj) {
9196         continue;
9197       }
9198 
9199       switch (obj->header.type) {
9200       case GRN_TABLE_HASH_KEY :
9201       case GRN_TABLE_PAT_KEY :
9202       case GRN_TABLE_DAT_KEY :
9203         if (!obj->header.domain) {
9204           break;
9205         }
9206 
9207         domain = grn_ctx_at(ctx, obj->header.domain);
9208         if (!domain) {
9209           break;
9210         }
9211 
9212         switch (domain->header.type) {
9213         case GRN_TABLE_NO_KEY :
9214         case GRN_TABLE_HASH_KEY :
9215         case GRN_TABLE_PAT_KEY :
9216         case GRN_TABLE_DAT_KEY :
9217           rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9218           break;
9219         }
9220         break;
9221       }
9222 
9223       if (rc != GRN_SUCCESS) {
9224         break;
9225       }
9226     }
9227     grn_table_cursor_close(ctx, cur);
9228   }
9229   return rc;
9230 }
9231 
9232 static grn_rc
_grn_obj_remove_db_all_tables(grn_ctx * ctx,grn_obj * db)9233 _grn_obj_remove_db_all_tables(grn_ctx *ctx, grn_obj *db)
9234 {
9235   grn_rc rc = GRN_SUCCESS;
9236   grn_table_cursor *cur;
9237   if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9238     grn_id id;
9239     while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9240       grn_obj *obj = grn_ctx_at(ctx, id);
9241 
9242       if (!obj) {
9243         continue;
9244       }
9245 
9246       switch (obj->header.type) {
9247       case GRN_TABLE_NO_KEY :
9248       case GRN_TABLE_HASH_KEY :
9249       case GRN_TABLE_PAT_KEY :
9250       case GRN_TABLE_DAT_KEY :
9251         rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9252         break;
9253       }
9254 
9255       if (rc != GRN_SUCCESS) {
9256         break;
9257       }
9258     }
9259     grn_table_cursor_close(ctx, cur);
9260   }
9261   return rc;
9262 }
9263 
9264 static grn_rc
_grn_obj_remove_db(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path)9265 _grn_obj_remove_db(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9266                    const char *path)
9267 {
9268   grn_rc rc = GRN_SUCCESS;
9269   const char *io_spath;
9270   char *spath;
9271   grn_db *s = (grn_db *)db;
9272   unsigned char key_type;
9273 
9274   rc = _grn_obj_remove_db_index_columns(ctx, db);
9275   if (rc != GRN_SUCCESS) { return rc; }
9276   rc = _grn_obj_remove_db_reference_columns(ctx, db);
9277   if (rc != GRN_SUCCESS) { return rc; }
9278   rc = _grn_obj_remove_db_reference_tables(ctx, db);
9279   if (rc != GRN_SUCCESS) { return rc; }
9280   rc = _grn_obj_remove_db_all_tables(ctx, db);
9281   if (rc != GRN_SUCCESS) { return rc; }
9282 
9283   if (s->specs &&
9284       (io_spath = grn_obj_path(ctx, (grn_obj *)s->specs)) && *io_spath != '\0') {
9285     if (!(spath = GRN_STRDUP(io_spath))) {
9286       ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_spath);
9287       return ctx->rc;
9288     }
9289   } else {
9290     spath = NULL;
9291   }
9292 
9293   key_type = s->keys->header.type;
9294 
9295   rc = grn_obj_close(ctx, obj);
9296   if (rc != GRN_SUCCESS) {
9297     if (spath) {
9298       GRN_FREE(spath);
9299     }
9300     return rc;
9301   }
9302 
9303   if (spath) {
9304     rc = grn_ja_remove(ctx, spath);
9305     GRN_FREE(spath);
9306     if (rc != GRN_SUCCESS) { return rc; }
9307   }
9308 
9309   if (path) {
9310     switch (key_type) {
9311     case GRN_TABLE_PAT_KEY :
9312       rc = grn_pat_remove(ctx, path);
9313       break;
9314     case GRN_TABLE_DAT_KEY :
9315       rc = grn_dat_remove(ctx, path);
9316       break;
9317     }
9318     if (rc == GRN_SUCCESS) {
9319       rc = grn_db_config_remove(ctx, path);
9320     } else {
9321       grn_db_config_remove(ctx, path);
9322     }
9323   }
9324 
9325   return rc;
9326 }
9327 
9328 static grn_rc
remove_reference_tables(grn_ctx * ctx,grn_obj * table,grn_obj * db)9329 remove_reference_tables(grn_ctx *ctx, grn_obj *table, grn_obj *db)
9330 {
9331   grn_rc rc = GRN_SUCCESS;
9332   grn_bool is_close_opened_object_mode = GRN_FALSE;
9333   grn_id table_id;
9334   char table_name[GRN_TABLE_MAX_KEY_SIZE];
9335   int table_name_size;
9336   grn_table_cursor *cursor;
9337 
9338   if (grn_thread_get_limit() == 1) {
9339     is_close_opened_object_mode = GRN_TRUE;
9340   }
9341 
9342   table_id = DB_OBJ(table)->id;
9343   table_name_size = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
9344   if ((cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
9345                                       GRN_CURSOR_BY_ID))) {
9346     grn_id id;
9347     while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
9348       grn_obj *object;
9349       grn_bool is_removed = GRN_FALSE;
9350 
9351       if (is_close_opened_object_mode) {
9352         grn_ctx_push_temporary_open_space(ctx);
9353       }
9354 
9355       object = grn_ctx_at(ctx, id);
9356       if (!object) {
9357         ERRCLR(ctx);
9358         if (is_close_opened_object_mode) {
9359           grn_ctx_pop_temporary_open_space(ctx);
9360         }
9361         continue;
9362       }
9363 
9364       switch (object->header.type) {
9365       case GRN_TABLE_HASH_KEY :
9366       case GRN_TABLE_PAT_KEY :
9367       case GRN_TABLE_DAT_KEY :
9368         if (DB_OBJ(object)->id == table_id) {
9369           break;
9370         }
9371 
9372         if (object->header.domain == table_id) {
9373           rc = _grn_obj_remove(ctx, object, GRN_TRUE);
9374           is_removed = (grn_table_at(ctx, db, id) == GRN_ID_NIL);
9375         }
9376         break;
9377       case GRN_TABLE_NO_KEY :
9378         break;
9379       case GRN_COLUMN_VAR_SIZE :
9380       case GRN_COLUMN_FIX_SIZE :
9381         if (object->header.domain == table_id) {
9382           break;
9383         }
9384         if (DB_OBJ(object)->range == table_id) {
9385           rc = _grn_obj_remove(ctx, object, GRN_FALSE);
9386           is_removed = (grn_table_at(ctx, db, id) == GRN_ID_NIL);
9387         }
9388         break;
9389       case GRN_COLUMN_INDEX :
9390         break;
9391       default:
9392         break;
9393       }
9394 
9395       if (!is_removed) {
9396         grn_obj_unlink(ctx, object);
9397       }
9398 
9399       if (is_close_opened_object_mode) {
9400         grn_ctx_pop_temporary_open_space(ctx);
9401       }
9402 
9403       if (rc != GRN_SUCCESS) {
9404         break;
9405       }
9406     }
9407     grn_table_cursor_close(ctx, cursor);
9408   }
9409 
9410   return rc;
9411 }
9412 
9413 static grn_bool
is_removable_table(grn_ctx * ctx,grn_obj * table,grn_obj * db)9414 is_removable_table(grn_ctx *ctx, grn_obj *table, grn_obj *db)
9415 {
9416   grn_id table_id;
9417   grn_id reference_object_id;
9418 
9419   table_id = DB_OBJ(table)->id;
9420   if (table_id & GRN_OBJ_TMP_OBJECT) {
9421     return GRN_TRUE;
9422   }
9423 
9424   reference_object_id = grn_table_find_reference_object(ctx, table);
9425   if (reference_object_id == GRN_ID_NIL) {
9426     return GRN_TRUE;
9427   }
9428 
9429   {
9430     grn_obj *db;
9431     const char *table_name;
9432     int table_name_size;
9433     grn_obj *reference_object;
9434     const char *reference_object_name;
9435     int reference_object_name_size;
9436 
9437     db = grn_ctx_db(ctx);
9438 
9439     table_name = _grn_table_key(ctx, db, table_id,&table_name_size);
9440 
9441     reference_object = grn_ctx_at(ctx, reference_object_id);
9442     reference_object_name = _grn_table_key(ctx,
9443                                            db,
9444                                            reference_object_id,
9445                                            &reference_object_name_size);
9446     if (reference_object) {
9447       if (grn_obj_is_table(ctx, reference_object)) {
9448         ERR(GRN_OPERATION_NOT_PERMITTED,
9449             "[table][remove] a table that references the table exists: "
9450             "<%.*s._key> -> <%.*s>",
9451             reference_object_name_size, reference_object_name,
9452             table_name_size, table_name);
9453       } else {
9454         ERR(GRN_OPERATION_NOT_PERMITTED,
9455             "[table][remove] a column that references the table exists: "
9456             "<%.*s> -> <%.*s>",
9457             reference_object_name_size, reference_object_name,
9458             table_name_size, table_name);
9459       }
9460     } else {
9461       ERR(GRN_OPERATION_NOT_PERMITTED,
9462           "[table][remove] a dangling object that references the table exists: "
9463           "<%.*s(%u)> -> <%.*s>",
9464           reference_object_name_size,
9465           reference_object_name,
9466           reference_object_id,
9467           table_name_size, table_name);
9468     }
9469   }
9470 
9471   return GRN_FALSE;
9472 }
9473 
9474 static inline grn_rc
_grn_obj_remove_spec(grn_ctx * ctx,grn_obj * db,grn_id id,uint8_t type)9475 _grn_obj_remove_spec(grn_ctx *ctx, grn_obj *db, grn_id id, uint8_t type)
9476 {
9477   const char *name;
9478   uint32_t name_size = 0;
9479 
9480   name = _grn_table_key(ctx, db, id, &name_size);
9481   /* TODO: reduce log level. */
9482   GRN_LOG(ctx, GRN_LOG_NOTICE,
9483           "spec:%u:remove:%.*s:%u(%s)",
9484           id,
9485           name_size, name,
9486           type,
9487           grn_obj_type_to_string(type));
9488 
9489   return grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
9490 }
9491 
9492 static grn_rc
_grn_obj_remove_pat(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path,grn_bool dependent)9493 _grn_obj_remove_pat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9494                     const char *path, grn_bool dependent)
9495 {
9496   grn_rc rc = GRN_SUCCESS;
9497   uint8_t type;
9498 
9499   type = obj->header.type;
9500 
9501   if (dependent) {
9502     rc = remove_reference_tables(ctx, obj, db);
9503     if (rc != GRN_SUCCESS) {
9504       return rc;
9505     }
9506   } else {
9507     if (!is_removable_table(ctx, obj, db)) {
9508       return ctx->rc;
9509     }
9510   }
9511 
9512   rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
9513   if (rc != GRN_SUCCESS) { return rc; }
9514   rc = remove_columns(ctx, obj);
9515   if (rc != GRN_SUCCESS) { return rc; }
9516 
9517   rc = grn_obj_close(ctx, obj);
9518   if (rc != GRN_SUCCESS) { return rc; }
9519 
9520   if (path) {
9521     rc = grn_pat_remove(ctx, path);
9522     if (rc != GRN_SUCCESS) { return rc; }
9523     rc = _grn_obj_remove_spec(ctx, db, id, type);
9524     if (rc != GRN_SUCCESS) { return rc; }
9525     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9526     if (rc != GRN_SUCCESS) { return rc; }
9527   }
9528 
9529   grn_obj_touch(ctx, db, NULL);
9530 
9531   return rc;
9532 }
9533 
9534 static grn_rc
_grn_obj_remove_dat(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path,grn_bool dependent)9535 _grn_obj_remove_dat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9536                     const char *path, grn_bool dependent)
9537 {
9538   grn_rc rc = GRN_SUCCESS;
9539   uint8_t type;
9540 
9541   type = obj->header.type;
9542 
9543   if (dependent) {
9544     rc = remove_reference_tables(ctx, obj, db);
9545     if (rc != GRN_SUCCESS) {
9546       return rc;
9547     }
9548   } else {
9549     if (!is_removable_table(ctx, obj, db)) {
9550       return ctx->rc;
9551     }
9552   }
9553 
9554   rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
9555   if (rc != GRN_SUCCESS) { return rc; }
9556   rc = remove_columns(ctx, obj);
9557   if (rc != GRN_SUCCESS) { return rc; }
9558 
9559   rc = grn_obj_close(ctx, obj);
9560   if (rc != GRN_SUCCESS) { return rc; }
9561 
9562   if (path) {
9563     rc = grn_dat_remove(ctx, path);
9564     if (rc != GRN_SUCCESS) { return rc; }
9565     rc = _grn_obj_remove_spec(ctx, db, id, type);
9566     if (rc != GRN_SUCCESS) { return rc; }
9567     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9568     if (rc != GRN_SUCCESS) { return rc; }
9569   }
9570 
9571   grn_obj_touch(ctx, db, NULL);
9572 
9573   return rc;
9574 }
9575 
9576 static grn_rc
_grn_obj_remove_hash(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path,grn_bool dependent)9577 _grn_obj_remove_hash(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9578                      const char *path, grn_bool dependent)
9579 {
9580   grn_rc rc = GRN_SUCCESS;
9581   uint8_t type;
9582 
9583   type = obj->header.type;
9584 
9585   if (dependent) {
9586     rc = remove_reference_tables(ctx, obj, db);
9587     if (rc != GRN_SUCCESS) {
9588       return rc;
9589     }
9590   } else {
9591     if (!is_removable_table(ctx, obj, db)) {
9592       return ctx->rc;
9593     }
9594   }
9595 
9596   rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
9597   if (rc != GRN_SUCCESS) { return rc; }
9598   rc = remove_columns(ctx, obj);
9599   if (rc != GRN_SUCCESS) { return rc; }
9600 
9601   rc = grn_obj_close(ctx, obj);
9602   if (rc != GRN_SUCCESS) { return rc; }
9603 
9604   if (path) {
9605     rc = grn_hash_remove(ctx, path);
9606     if (rc != GRN_SUCCESS) { return rc; }
9607     rc = _grn_obj_remove_spec(ctx, db, id, type);
9608     if (rc != GRN_SUCCESS) { return rc; }
9609     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9610     if (rc != GRN_SUCCESS) { return rc; }
9611   }
9612 
9613   grn_obj_touch(ctx, db, NULL);
9614 
9615   return rc;
9616 }
9617 
9618 static grn_rc
_grn_obj_remove_array(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path,grn_bool dependent)9619 _grn_obj_remove_array(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9620                       const char *path, grn_bool dependent)
9621 {
9622   grn_rc rc = GRN_SUCCESS;
9623   uint8_t type;
9624 
9625   type = obj->header.type;
9626 
9627   if (dependent) {
9628     rc = remove_reference_tables(ctx, obj, db);
9629     if (rc != GRN_SUCCESS) {
9630       return rc;
9631     }
9632   } else {
9633     if (!is_removable_table(ctx, obj, db)) {
9634       return ctx->rc;
9635     }
9636   }
9637 
9638   rc = remove_columns(ctx, obj);
9639   if (rc != GRN_SUCCESS) { return rc; }
9640 
9641   rc = grn_obj_close(ctx, obj);
9642   if (rc != GRN_SUCCESS) { return rc; }
9643 
9644   if (path) {
9645     rc = grn_array_remove(ctx, path);
9646     if (rc != GRN_SUCCESS) { return rc; }
9647     rc = _grn_obj_remove_spec(ctx, db, id, type);
9648     if (rc != GRN_SUCCESS) { return rc; }
9649     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9650     if (rc != GRN_SUCCESS) { return rc; }
9651   }
9652 
9653   grn_obj_touch(ctx, db, NULL);
9654 
9655   return rc;
9656 }
9657 
9658 static grn_rc
_grn_obj_remove_ja(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path)9659 _grn_obj_remove_ja(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9660                    const char *path)
9661 {
9662   grn_rc rc = GRN_SUCCESS;
9663   uint8_t type;
9664 
9665   type = obj->header.type;
9666 
9667   rc = remove_index(ctx, obj, GRN_HOOK_SET);
9668   if (rc != GRN_SUCCESS) { return rc; }
9669   rc = grn_obj_close(ctx, obj);
9670   if (rc != GRN_SUCCESS) { return rc; }
9671 
9672   if (path) {
9673     rc = grn_ja_remove(ctx, path);
9674     if (rc != GRN_SUCCESS) { return rc; }
9675     rc = _grn_obj_remove_spec(ctx, db, id, type);
9676     if (rc != GRN_SUCCESS) { return rc; }
9677     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9678     if (rc != GRN_SUCCESS) { return rc; }
9679   }
9680 
9681   grn_obj_touch(ctx, db, NULL);
9682 
9683   return rc;
9684 }
9685 
9686 static grn_rc
_grn_obj_remove_ra(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path)9687 _grn_obj_remove_ra(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9688                    const char *path)
9689 {
9690   grn_rc rc = GRN_SUCCESS;
9691   uint8_t type;
9692 
9693   type = obj->header.type;
9694 
9695   rc = remove_index(ctx, obj, GRN_HOOK_SET);
9696   if (rc != GRN_SUCCESS) { return rc; }
9697   rc = grn_obj_close(ctx, obj);
9698   if (rc != GRN_SUCCESS) { return rc; }
9699 
9700   if (path) {
9701     rc = grn_ra_remove(ctx, path);
9702     if (rc != GRN_SUCCESS) { return rc; }
9703     rc = _grn_obj_remove_spec(ctx, db, id, type);
9704     if (rc != GRN_SUCCESS) { return rc; }
9705     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9706     if (rc != GRN_SUCCESS) { return rc; }
9707   }
9708   grn_obj_touch(ctx, db, NULL);
9709 
9710   return rc;
9711 }
9712 
9713 static grn_rc
_grn_obj_remove_index(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path)9714 _grn_obj_remove_index(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9715                       const char *path)
9716 {
9717   grn_rc rc = GRN_SUCCESS;
9718   uint8_t type;
9719 
9720   type = obj->header.type;
9721 
9722   delete_source_hook(ctx, obj);
9723   rc = grn_obj_close(ctx, obj);
9724   if (rc != GRN_SUCCESS) { return rc; }
9725 
9726   if (path) {
9727     rc = grn_ii_remove(ctx, path);
9728     if (rc != GRN_SUCCESS) { return rc; }
9729     rc = _grn_obj_remove_spec(ctx, db, id, type);
9730     if (rc != GRN_SUCCESS) { return rc; }
9731     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9732     if (rc != GRN_SUCCESS) { return rc; }
9733   }
9734 
9735   grn_obj_touch(ctx, db, NULL);
9736 
9737   return rc;
9738 }
9739 
9740 static grn_rc
_grn_obj_remove_db_obj(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path)9741 _grn_obj_remove_db_obj(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9742                        const char *path)
9743 {
9744   grn_rc rc = GRN_SUCCESS;
9745   uint8_t type;
9746 
9747   type = obj->header.type;
9748 
9749   rc = grn_obj_close(ctx, obj);
9750   if (rc != GRN_SUCCESS) { return rc; }
9751 
9752   if (path) {
9753     rc = grn_io_remove(ctx, path);
9754     if (rc != GRN_SUCCESS) { return rc; }
9755   }
9756 
9757   if (!(id & GRN_OBJ_TMP_OBJECT)) {
9758     rc = _grn_obj_remove_spec(ctx, db, id, type);
9759     if (rc != GRN_SUCCESS) { return rc; }
9760     rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9761     if (rc != GRN_SUCCESS) { return rc; }
9762   }
9763 
9764   grn_obj_touch(ctx, db, NULL);
9765 
9766   return rc;
9767 }
9768 
9769 static grn_rc
_grn_obj_remove_other(grn_ctx * ctx,grn_obj * obj,grn_obj * db,grn_id id,const char * path)9770 _grn_obj_remove_other(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9771                       const char *path)
9772 {
9773   return grn_obj_close(ctx, obj);
9774 }
9775 
9776 static grn_rc
_grn_obj_remove(grn_ctx * ctx,grn_obj * obj,grn_bool dependent)9777 _grn_obj_remove(grn_ctx *ctx, grn_obj *obj, grn_bool dependent)
9778 {
9779   grn_rc rc = GRN_SUCCESS;
9780   grn_id id = GRN_ID_NIL;
9781   grn_obj *db = NULL;
9782   const char *io_path;
9783   char *path;
9784   grn_bool is_temporary_open_target = GRN_FALSE;
9785 
9786   if (ctx->impl && ctx->impl->db) {
9787     grn_id id;
9788     uint32_t s = 0;
9789     const char *n;
9790 
9791     id = DB_OBJ(obj)->id;
9792     n = _grn_table_key(ctx, ctx->impl->db, id, &s);
9793     if (s > 0) {
9794       GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:%u:obj_remove %.*s", id, s, n);
9795     }
9796   }
9797   if (obj->header.type != GRN_PROC &&
9798       (io_path = grn_obj_path(ctx, obj)) && *io_path != '\0') {
9799     if (!(path = GRN_STRDUP(io_path))) {
9800       ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
9801       return ctx->rc;
9802     }
9803   } else {
9804     path = NULL;
9805   }
9806   if (GRN_DB_OBJP(obj)) {
9807     id = DB_OBJ(obj)->id;
9808     db = DB_OBJ(obj)->db;
9809   }
9810   switch (obj->header.type) {
9811   case GRN_DB :
9812     rc = _grn_obj_remove_db(ctx, obj, db, id, path);
9813     break;
9814   case GRN_TABLE_PAT_KEY :
9815     rc = _grn_obj_remove_pat(ctx, obj, db, id, path, dependent);
9816     is_temporary_open_target = GRN_TRUE;
9817     break;
9818   case GRN_TABLE_DAT_KEY :
9819     rc = _grn_obj_remove_dat(ctx, obj, db, id, path, dependent);
9820     is_temporary_open_target = GRN_TRUE;
9821     break;
9822   case GRN_TABLE_HASH_KEY :
9823     rc = _grn_obj_remove_hash(ctx, obj, db, id, path, dependent);
9824     is_temporary_open_target = GRN_TRUE;
9825     break;
9826   case GRN_TABLE_NO_KEY :
9827     rc = _grn_obj_remove_array(ctx, obj, db, id, path, dependent);
9828     is_temporary_open_target = GRN_TRUE;
9829     break;
9830   case GRN_COLUMN_VAR_SIZE :
9831     rc = _grn_obj_remove_ja(ctx, obj, db, id, path);
9832     is_temporary_open_target = GRN_TRUE;
9833     break;
9834   case GRN_COLUMN_FIX_SIZE :
9835     rc = _grn_obj_remove_ra(ctx, obj, db, id, path);
9836     is_temporary_open_target = GRN_TRUE;
9837     break;
9838   case GRN_COLUMN_INDEX :
9839     rc = _grn_obj_remove_index(ctx, obj, db, id, path);
9840     is_temporary_open_target = GRN_TRUE;
9841     break;
9842   default :
9843     if (GRN_DB_OBJP(obj)) {
9844       rc = _grn_obj_remove_db_obj(ctx, obj, db, id, path);
9845     } else {
9846       rc = _grn_obj_remove_other(ctx, obj, db, id, path);
9847     }
9848   }
9849   if (path) {
9850     GRN_FREE(path);
9851   } else {
9852     is_temporary_open_target = GRN_FALSE;
9853   }
9854 
9855   if (is_temporary_open_target && rc == GRN_SUCCESS) {
9856     grn_obj *space;
9857     space = ctx->impl->temporary_open_spaces.current;
9858     if (space) {
9859       unsigned int i, n_elements;
9860       n_elements = GRN_BULK_VSIZE(space) / sizeof(grn_obj *);
9861       for (i = 0; i < n_elements; i++) {
9862         if (GRN_PTR_VALUE_AT(space, i) == obj) {
9863           GRN_PTR_SET_AT(ctx, space, i, NULL);
9864         }
9865       }
9866     }
9867   }
9868 
9869   return rc;
9870 }
9871 
9872 grn_rc
grn_obj_remove(grn_ctx * ctx,grn_obj * obj)9873 grn_obj_remove(grn_ctx *ctx, grn_obj *obj)
9874 {
9875   grn_rc rc = GRN_SUCCESS;
9876   GRN_API_ENTER;
9877   if (ctx->impl && ctx->impl->db && ctx->impl->db != obj) {
9878     grn_io *io = grn_obj_get_io(ctx, ctx->impl->db);
9879     rc = grn_io_lock(ctx, io, grn_lock_timeout);
9880     if (rc == GRN_SUCCESS) {
9881       rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9882       grn_io_unlock(io);
9883     }
9884   } else {
9885     rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9886   }
9887   GRN_API_RETURN(rc);
9888 }
9889 
9890 grn_rc
grn_obj_remove_dependent(grn_ctx * ctx,grn_obj * obj)9891 grn_obj_remove_dependent(grn_ctx *ctx, grn_obj *obj)
9892 {
9893   grn_rc rc = GRN_SUCCESS;
9894   GRN_API_ENTER;
9895   if (ctx->impl && ctx->impl->db && ctx->impl->db != obj) {
9896     grn_io *io = grn_obj_get_io(ctx, ctx->impl->db);
9897     rc = grn_io_lock(ctx, io, grn_lock_timeout);
9898     if (rc == GRN_SUCCESS) {
9899       rc = _grn_obj_remove(ctx, obj, GRN_TRUE);
9900       grn_io_unlock(io);
9901     }
9902   } else {
9903     rc = _grn_obj_remove(ctx, obj, GRN_TRUE);
9904   }
9905   GRN_API_RETURN(rc);
9906 }
9907 
9908 grn_rc
grn_obj_remove_force(grn_ctx * ctx,const char * name,int name_size)9909 grn_obj_remove_force(grn_ctx *ctx, const char *name, int name_size)
9910 {
9911   grn_rc rc = GRN_SUCCESS;
9912   grn_obj *db;
9913   grn_id obj_id;
9914   char path[PATH_MAX];
9915 
9916   GRN_API_ENTER;
9917 
9918   if (!(ctx->impl && ctx->impl->db)) {
9919     ERR(GRN_INVALID_ARGUMENT,
9920         "[object][remove][force] database isn't initialized");
9921     rc = ctx->rc;
9922     goto exit;
9923   }
9924 
9925   db = ctx->impl->db;
9926   if (name_size == -1) {
9927     name_size = strlen(name);
9928   }
9929   obj_id = grn_table_get(ctx, db, name, name_size);
9930   if (obj_id == GRN_ID_NIL) {
9931     ERR(GRN_INVALID_ARGUMENT,
9932         "[object][remove][force] nonexistent object: <%.*s>",
9933         name_size, name);
9934     rc = ctx->rc;
9935     goto exit;
9936   }
9937 
9938   grn_obj_delete_by_id(ctx, db, obj_id, GRN_TRUE);
9939   grn_obj_path_by_id(ctx, db, obj_id, path);
9940   grn_io_remove_if_exist(ctx, path);
9941   grn_strcat(path, PATH_MAX, ".c");
9942   grn_io_remove_if_exist(ctx, path);
9943 
9944 exit :
9945   GRN_API_RETURN(rc);
9946 }
9947 
9948 grn_rc
grn_table_update_by_id(grn_ctx * ctx,grn_obj * table,grn_id id,const void * dest_key,unsigned int dest_key_size)9949 grn_table_update_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
9950                        const void *dest_key, unsigned int dest_key_size)
9951 {
9952   grn_rc rc = GRN_OPERATION_NOT_SUPPORTED;
9953   GRN_API_ENTER;
9954   if (table->header.type == GRN_TABLE_DAT_KEY) {
9955     grn_dat *dat = (grn_dat *)table;
9956     if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
9957       if (grn_io_lock(ctx, dat->io, grn_lock_timeout)) {
9958         rc = ctx->rc;
9959       } else {
9960         rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
9961         grn_io_unlock(dat->io);
9962       }
9963     } else {
9964       rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
9965     }
9966   }
9967   GRN_API_RETURN(rc);
9968 }
9969 
9970 grn_rc
grn_table_update(grn_ctx * ctx,grn_obj * table,const void * src_key,unsigned int src_key_size,const void * dest_key,unsigned int dest_key_size)9971 grn_table_update(grn_ctx *ctx, grn_obj *table,
9972                  const void *src_key, unsigned int src_key_size,
9973                  const void *dest_key, unsigned int dest_key_size)
9974 {
9975   grn_rc rc = GRN_OPERATION_NOT_SUPPORTED;
9976   GRN_API_ENTER;
9977   if (table->header.type == GRN_TABLE_DAT_KEY) {
9978     rc = grn_dat_update(ctx, (grn_dat *)table,
9979                         src_key, src_key_size,
9980                         dest_key, dest_key_size);
9981   }
9982   GRN_API_RETURN(rc);
9983 }
9984 
9985 grn_rc
grn_obj_rename(grn_ctx * ctx,grn_obj * obj,const char * name,unsigned int name_size)9986 grn_obj_rename(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
9987 {
9988   grn_rc rc = GRN_INVALID_ARGUMENT;
9989   GRN_API_ENTER;
9990   if (ctx && ctx->impl && GRN_DB_P(ctx->impl->db) && GRN_DB_OBJP(obj) && !IS_TEMP(obj)) {
9991     grn_db *s = (grn_db *)ctx->impl->db;
9992     grn_obj *keys = (grn_obj *)s->keys;
9993     rc = grn_table_update_by_id(ctx, keys, DB_OBJ(obj)->id, name, name_size);
9994   }
9995   GRN_API_RETURN(rc);
9996 }
9997 
9998 grn_rc
grn_table_rename(grn_ctx * ctx,grn_obj * table,const char * name,unsigned int name_size)9999 grn_table_rename(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
10000 {
10001   grn_rc rc = GRN_INVALID_ARGUMENT;
10002   grn_hash *cols;
10003 
10004   GRN_API_ENTER;
10005 
10006   if (!GRN_OBJ_TABLEP(table)) {
10007     char table_name[GRN_TABLE_MAX_KEY_SIZE];
10008     int table_name_size;
10009     table_name_size = grn_obj_name(ctx, table, table_name,
10010                                    GRN_TABLE_MAX_KEY_SIZE);
10011     rc = GRN_INVALID_ARGUMENT;
10012     ERR(rc,
10013         "[table][rename] isn't table: <%.*s> -> <%.*s>",
10014         table_name_size, table_name,
10015         name_size, name);
10016     goto exit;
10017   }
10018   if (IS_TEMP(table)) {
10019     rc = GRN_INVALID_ARGUMENT;
10020     ERR(rc,
10021         "[table][rename] temporary table doesn't have name: "
10022         "(anonymous) -> <%.*s>",
10023         name_size, name);
10024     goto exit;
10025   }
10026 
10027   if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
10028                               GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
10029     grn_table_columns(ctx, table, "", 0, (grn_obj *)cols);
10030     if (!(rc = grn_obj_rename(ctx, table, name, name_size))) {
10031       grn_id *key;
10032       char fullname[GRN_TABLE_MAX_KEY_SIZE];
10033       grn_memcpy(fullname, name, name_size);
10034       fullname[name_size] = GRN_DB_DELIMITER;
10035       GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
10036         grn_obj *col = grn_ctx_at(ctx, *key);
10037         if (col) {
10038           int colname_len = grn_column_name(ctx, col, fullname + name_size + 1,
10039                                             GRN_TABLE_MAX_KEY_SIZE - name_size - 1);
10040           if (colname_len) {
10041             if ((rc = grn_obj_rename(ctx, col, fullname,
10042                                      name_size + 1 + colname_len))) {
10043               break;
10044             }
10045           }
10046         }
10047       });
10048     }
10049     grn_hash_close(ctx, cols);
10050   }
10051 exit:
10052   GRN_API_RETURN(rc);
10053 }
10054 
10055 grn_rc
grn_column_rename(grn_ctx * ctx,grn_obj * column,const char * name,unsigned int name_size)10056 grn_column_rename(grn_ctx *ctx, grn_obj *column, const char *name, unsigned int name_size)
10057 {
10058   grn_rc rc = GRN_INVALID_ARGUMENT;
10059   GRN_API_ENTER;
10060   if (GRN_DB_OBJP(column)) {
10061     char fullname[GRN_TABLE_MAX_KEY_SIZE];
10062     grn_db *s = (grn_db *)DB_OBJ(column)->db;
10063     int len = grn_table_get_key(ctx, s->keys, DB_OBJ(column)->header.domain,
10064                                 fullname, GRN_TABLE_MAX_KEY_SIZE);
10065     if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
10066       ERR(GRN_INVALID_ARGUMENT,
10067           "[column][rename] too long column name: required name_size(%d) < %d"
10068           ": <%.*s>.<%.*s>",
10069           name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - len,
10070           len, fullname, name_size, name);
10071       goto exit;
10072     }
10073     fullname[len] = GRN_DB_DELIMITER;
10074     grn_memcpy(fullname + len + 1, name, name_size);
10075     name_size += len + 1;
10076     rc = grn_obj_rename(ctx, column, fullname, name_size);
10077     if (rc == GRN_SUCCESS) {
10078       grn_obj_touch(ctx, column, NULL);
10079     }
10080   }
10081 exit :
10082   GRN_API_RETURN(rc);
10083 }
10084 
10085 grn_rc
grn_obj_path_rename(grn_ctx * ctx,const char * old_path,const char * new_path)10086 grn_obj_path_rename(grn_ctx *ctx, const char *old_path, const char *new_path)
10087 {
10088   GRN_API_ENTER;
10089   GRN_API_RETURN(GRN_SUCCESS);
10090 }
10091 
10092 /* db must be validated by caller */
10093 grn_id
grn_obj_register(grn_ctx * ctx,grn_obj * db,const char * name,unsigned int name_size)10094 grn_obj_register(grn_ctx *ctx, grn_obj *db, const char *name, unsigned int name_size)
10095 {
10096   grn_id id = GRN_ID_NIL;
10097   if (name && name_size) {
10098     grn_db *s = (grn_db *)db;
10099     int added;
10100     if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
10101       grn_rc rc;
10102       rc = ctx->rc;
10103       if (rc == GRN_SUCCESS) {
10104         rc = GRN_NO_MEMORY_AVAILABLE;
10105       }
10106       ERR(rc,
10107           "[object][register] failed to register a name: <%.*s>%s%s%s",
10108           name_size, name,
10109           ctx->rc == GRN_SUCCESS ? "" : ": <",
10110           ctx->rc == GRN_SUCCESS ? "" : ctx->errbuf,
10111           ctx->rc == GRN_SUCCESS ? "" : ">");
10112     } else if (!added) {
10113       ERR(GRN_INVALID_ARGUMENT,
10114           "[object][register] already used name was assigned: <%.*s>",
10115           name_size, name);
10116       id = GRN_ID_NIL;
10117     }
10118   } else if (ctx->impl && ctx->impl->values) {
10119     id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
10120   }
10121   return id;
10122 }
10123 
10124 grn_rc
grn_obj_delete_by_id(grn_ctx * ctx,grn_obj * db,grn_id id,grn_bool removep)10125 grn_obj_delete_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, grn_bool removep)
10126 {
10127   grn_rc rc = GRN_INVALID_ARGUMENT;
10128   GRN_API_ENTER;
10129   if (id) {
10130     if (id & GRN_OBJ_TMP_OBJECT) {
10131       if (ctx->impl) {
10132         if (id & GRN_OBJ_TMP_COLUMN) {
10133           if (ctx->impl->temporary_columns) {
10134             rc = grn_pat_delete_by_id(ctx, ctx->impl->temporary_columns,
10135                                       id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT),
10136                                       NULL);
10137           }
10138         } else {
10139           if (ctx->impl->values) {
10140             rc = grn_array_delete_by_id(ctx, ctx->impl->values,
10141                                         id & ~GRN_OBJ_TMP_OBJECT, NULL);
10142           }
10143         }
10144       }
10145     } else {
10146       db_value *vp;
10147       grn_db *s = (grn_db *)db;
10148       if ((vp = grn_tiny_array_at(&s->values, id))) {
10149         GRN_ASSERT(!vp->lock);
10150         vp->lock = 0;
10151         vp->ptr = NULL;
10152         vp->done = 0;
10153       }
10154       if (removep) {
10155         switch (s->keys->header.type) {
10156         case GRN_TABLE_PAT_KEY :
10157           rc = grn_pat_delete_by_id(ctx, (grn_pat *)s->keys, id, NULL);
10158           break;
10159         case GRN_TABLE_DAT_KEY :
10160           rc = grn_dat_delete_by_id(ctx, (grn_dat *)s->keys, id, NULL);
10161           break;
10162         }
10163       } else {
10164         rc = GRN_SUCCESS;
10165       }
10166     }
10167   }
10168   GRN_API_RETURN(rc);
10169 }
10170 
10171 
10172 grn_rc
grn_obj_path_by_id(grn_ctx * ctx,grn_obj * db,grn_id id,char * buffer)10173 grn_obj_path_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, char *buffer)
10174 {
10175   grn_rc rc = GRN_SUCCESS;
10176   GRN_API_ENTER;
10177   if (!GRN_DB_P(db) || !buffer) {
10178     rc = GRN_INVALID_ARGUMENT;
10179   } else {
10180     grn_db_generate_pathname(ctx, db, id, buffer);
10181   }
10182   GRN_API_RETURN(rc);
10183 }
10184 
10185 /* db must be validated by caller */
10186 grn_rc
grn_db_obj_init(grn_ctx * ctx,grn_obj * db,grn_id id,grn_db_obj * obj)10187 grn_db_obj_init(grn_ctx *ctx, grn_obj *db, grn_id id, grn_db_obj *obj)
10188 {
10189   grn_rc rc = GRN_SUCCESS;
10190   if (id) {
10191     if (id & GRN_OBJ_TMP_OBJECT) {
10192       if (id & GRN_OBJ_TMP_COLUMN) {
10193         if (ctx->impl && ctx->impl->temporary_columns) {
10194           grn_id real_id = id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT);
10195           rc = grn_pat_set_value(ctx, ctx->impl->temporary_columns,
10196                                  real_id, &obj, GRN_OBJ_SET);
10197         }
10198       } else {
10199         if (ctx->impl && ctx->impl->values) {
10200           rc = grn_array_set_value(ctx, ctx->impl->values,
10201                                    id & ~GRN_OBJ_TMP_OBJECT, &obj, GRN_OBJ_SET);
10202         }
10203       }
10204     } else {
10205       db_value *vp;
10206       vp = grn_tiny_array_at(&((grn_db *)db)->values, id);
10207       if (!vp) {
10208         rc = GRN_NO_MEMORY_AVAILABLE;
10209         ERR(rc, "grn_tiny_array_at failed (%d)", id);
10210         return rc;
10211       }
10212       vp->lock = 1;
10213       vp->ptr = (grn_obj *)obj;
10214     }
10215   }
10216   obj->id = id;
10217   obj->db = db;
10218   obj->source = NULL;
10219   obj->source_size = 0;
10220   {
10221     grn_hook_entry entry;
10222     for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
10223       obj->hooks[entry] = NULL;
10224     }
10225   }
10226   grn_obj_spec_save(ctx, obj);
10227   return rc;
10228 }
10229 
10230 #define GET_PATH(spec,decoded_spec,buffer,s,id) do {\
10231   if (spec->header.flags & GRN_OBJ_CUSTOM_NAME) {\
10232     const char *path;\
10233     unsigned int size = grn_vector_get_element(ctx,\
10234                                                decoded_spec,\
10235                                                GRN_SERIALIZED_SPEC_INDEX_PATH,\
10236                                                &path,\
10237                                                NULL,\
10238                                                NULL);\
10239     if (size > PATH_MAX) { ERR(GRN_FILENAME_TOO_LONG, "too long path"); }\
10240     grn_memcpy(buffer, path, size);\
10241     buffer[size] = '\0';\
10242   } else {\
10243     grn_db_generate_pathname(ctx, (grn_obj *)s, id, buffer);\
10244   }\
10245 } while (0)
10246 
10247 #define UNPACK_INFO(spec,decoded_spec) do {\
10248   if (vp->ptr) {\
10249     const char *p;\
10250     uint32_t size;\
10251     grn_db_obj *r = DB_OBJ(vp->ptr);\
10252     r->header = spec->header;\
10253     r->id = id;\
10254     r->range = spec->range;\
10255     r->db = (grn_obj *)s;\
10256     size = grn_vector_get_element(ctx,\
10257                                   decoded_spec,\
10258                                   GRN_SERIALIZED_SPEC_INDEX_SOURCE,\
10259                                   &p,\
10260                                   NULL,\
10261                                   NULL);\
10262     if (size) {\
10263       if ((r->source = GRN_MALLOC(size))) {\
10264         grn_memcpy(r->source, p, size);\
10265         r->source_size = size;\
10266       }\
10267     }\
10268     size = grn_vector_get_element(ctx,\
10269                                   decoded_spec,\
10270                                   GRN_SERIALIZED_SPEC_INDEX_HOOK,\
10271                                   &p,\
10272                                   NULL,\
10273                                   NULL);\
10274     grn_hook_unpack(ctx, r, p, size);\
10275   }\
10276 } while (0)
10277 
10278 static void
grn_token_filters_unpack(grn_ctx * ctx,grn_obj * token_filters,grn_obj * spec_vector)10279 grn_token_filters_unpack(grn_ctx *ctx,
10280                          grn_obj *token_filters,
10281                          grn_obj *spec_vector)
10282 {
10283   grn_id *token_filter_ids;
10284   unsigned int element_size;
10285   unsigned int i, n_token_filter_ids;
10286 
10287   if (grn_vector_size(ctx, spec_vector) <= GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS) {
10288     return;
10289   }
10290 
10291   element_size = grn_vector_get_element(ctx,
10292                                         spec_vector,
10293                                         GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS,
10294                                         (const char **)(&token_filter_ids),
10295                                         NULL,
10296                                         NULL);
10297   n_token_filter_ids = element_size / sizeof(grn_id);
10298   for (i = 0; i < n_token_filter_ids; i++) {
10299     grn_id token_filter_id = token_filter_ids[i];
10300     grn_obj *token_filter;
10301 
10302     token_filter = grn_ctx_at(ctx, token_filter_id);
10303     if (!token_filter) {
10304       ERR(GRN_INVALID_ARGUMENT,
10305           "nonexistent token filter ID: %d", token_filter_id);
10306       return;
10307     }
10308     GRN_PTR_PUT(ctx, token_filters, token_filter);
10309   }
10310 }
10311 
10312 grn_bool
grn_db_spec_unpack(grn_ctx * ctx,grn_id id,void * encoded_spec,uint32_t encoded_spec_size,grn_obj_spec ** spec,grn_obj * decoded_spec,const char * error_message_tag)10313 grn_db_spec_unpack(grn_ctx *ctx,
10314                    grn_id id,
10315                    void *encoded_spec,
10316                    uint32_t encoded_spec_size,
10317                    grn_obj_spec **spec,
10318                    grn_obj *decoded_spec,
10319                    const char *error_message_tag)
10320 {
10321   grn_obj *db;
10322   grn_db *db_raw;
10323   grn_rc rc;
10324   uint32_t spec_size;
10325 
10326   db = ctx->impl->db;
10327   db_raw = (grn_db *)db;
10328 
10329   rc = grn_vector_decode(ctx,
10330                          decoded_spec,
10331                          encoded_spec,
10332                          encoded_spec_size);
10333   if (rc != GRN_SUCCESS) {
10334     const char *name;
10335     uint32_t name_size;
10336     name = _grn_table_key(ctx, db, id, &name_size);
10337     GRN_LOG((ctx), GRN_LOG_ERROR,
10338             "%s: failed to decode spec: <%u>(<%.*s>):<%u>: %s",
10339             error_message_tag,
10340             id,
10341             name_size, name,
10342             encoded_spec_size,
10343             grn_rc_to_string(rc));
10344     return GRN_FALSE;
10345   }
10346 
10347   spec_size = grn_vector_get_element(ctx,
10348                                      decoded_spec,
10349                                      GRN_SERIALIZED_SPEC_INDEX_SPEC,
10350                                      (const char **)spec,
10351                                      NULL,
10352                                      NULL);
10353   if (spec_size == 0) {
10354     const char *name;
10355     uint32_t name_size;
10356     name = _grn_table_key(ctx, db, id, &name_size);
10357     GRN_LOG(ctx, GRN_LOG_ERROR,
10358             "%s: spec value is empty: <%u>(<%.*s>)",
10359             error_message_tag,
10360             id,
10361             name_size, name);
10362     return GRN_FALSE;
10363   }
10364 
10365   return GRN_TRUE;
10366 }
10367 
10368 grn_obj *
grn_ctx_at(grn_ctx * ctx,grn_id id)10369 grn_ctx_at(grn_ctx *ctx, grn_id id)
10370 {
10371   grn_obj *res = NULL;
10372   if (!ctx || !ctx->impl || !id) { return res; }
10373   GRN_API_ENTER;
10374   if (id & GRN_OBJ_TMP_OBJECT) {
10375     if (id & GRN_OBJ_TMP_COLUMN) {
10376       if (ctx->impl->temporary_columns) {
10377         grn_id real_id = id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT);
10378         grn_obj **tmp_obj;
10379         uint32_t size;
10380         tmp_obj = (grn_obj **)grn_pat_get_value_(ctx,
10381                                                  ctx->impl->temporary_columns,
10382                                                  real_id,
10383                                                  &size);
10384         if (tmp_obj) {
10385           res = *tmp_obj;
10386         }
10387       }
10388     } else {
10389       if (ctx->impl->values) {
10390         grn_obj **tmp_obj;
10391         tmp_obj = _grn_array_get_value(ctx, ctx->impl->values,
10392                                        id & ~GRN_OBJ_TMP_OBJECT);
10393         if (tmp_obj) {
10394           res = *tmp_obj;
10395         }
10396       }
10397     }
10398   } else {
10399     grn_db *s = (grn_db *)ctx->impl->db;
10400     if (s) {
10401       db_value *vp;
10402       uint32_t l, *pl, ntrial;
10403       if (!(vp = grn_tiny_array_at(&s->values, id))) { goto exit; }
10404 #ifdef USE_NREF
10405       pl = &vp->lock;
10406       for (ntrial = 0;; ntrial++) {
10407         GRN_ATOMIC_ADD_EX(pl, 1, l);
10408         if (l < GRN_IO_MAX_REF) { break; }
10409         if (ntrial >= 10) {
10410           GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
10411           break;
10412         }
10413         GRN_ATOMIC_ADD_EX(pl, -1, l);
10414         GRN_FUTEX_WAIT(pl);
10415       }
10416 #endif /* USE_NREF */
10417       if (s->specs && !vp->ptr /* && !vp->done */) {
10418 #ifndef USE_NREF
10419         pl = &vp->lock;
10420         for (ntrial = 0;; ntrial++) {
10421           GRN_ATOMIC_ADD_EX(pl, 1, l);
10422           if (l < GRN_IO_MAX_REF) { break; }
10423           if (ntrial >= 10) {
10424             GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
10425             break;
10426           }
10427           GRN_ATOMIC_ADD_EX(pl, -1, l);
10428           GRN_FUTEX_WAIT(pl);
10429         }
10430 #endif /* USE_NREF */
10431         if (!l) {
10432           grn_io_win iw;
10433           uint32_t encoded_spec_size;
10434           void *encoded_spec;
10435 
10436           encoded_spec = grn_ja_ref(ctx, s->specs, id, &iw, &encoded_spec_size);
10437           if (encoded_spec) {
10438             grn_bool success;
10439             grn_obj_spec *spec;
10440             grn_obj decoded_spec;
10441 
10442             GRN_OBJ_INIT(&decoded_spec, GRN_VECTOR, 0, GRN_DB_TEXT);
10443             success = grn_db_spec_unpack(ctx,
10444                                          id,
10445                                          encoded_spec,
10446                                          encoded_spec_size,
10447                                          &spec,
10448                                          &decoded_spec,
10449                                          "grn_ctx_at");
10450             if (success) {
10451               char buffer[PATH_MAX];
10452               switch (spec->header.type) {
10453               case GRN_TYPE :
10454                 vp->ptr = (grn_obj *)grn_type_open(ctx, spec);
10455                 UNPACK_INFO(spec, &decoded_spec);
10456                 break;
10457               case GRN_TABLE_HASH_KEY :
10458                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10459                 vp->ptr = (grn_obj *)grn_hash_open(ctx, buffer);
10460                 if (vp->ptr) {
10461                   grn_hash *hash = (grn_hash *)(vp->ptr);
10462                   grn_obj_flags flags = vp->ptr->header.flags;
10463                   UNPACK_INFO(spec, &decoded_spec);
10464                   vp->ptr->header.flags = flags;
10465                   grn_token_filters_unpack(ctx,
10466                                            &(hash->token_filters),
10467                                            &decoded_spec);
10468                 }
10469                 break;
10470               case GRN_TABLE_PAT_KEY :
10471                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10472                 vp->ptr = (grn_obj *)grn_pat_open(ctx, buffer);
10473                 if (vp->ptr) {
10474                   grn_pat *pat = (grn_pat *)(vp->ptr);
10475                   grn_obj_flags flags = vp->ptr->header.flags;
10476                   UNPACK_INFO(spec, &decoded_spec);
10477                   vp->ptr->header.flags = flags;
10478                   grn_token_filters_unpack(ctx,
10479                                            &(pat->token_filters),
10480                                            &decoded_spec);
10481                 }
10482                 break;
10483               case GRN_TABLE_DAT_KEY :
10484                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10485                 vp->ptr = (grn_obj *)grn_dat_open(ctx, buffer);
10486                 if (vp->ptr) {
10487                   grn_dat *dat = (grn_dat *)(vp->ptr);
10488                   grn_obj_flags flags = vp->ptr->header.flags;
10489                   UNPACK_INFO(spec, &decoded_spec);
10490                   vp->ptr->header.flags = flags;
10491                   grn_token_filters_unpack(ctx,
10492                                            &(dat->token_filters),
10493                                            &decoded_spec);
10494                 }
10495                 break;
10496               case GRN_TABLE_NO_KEY :
10497                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10498                 vp->ptr = (grn_obj *)grn_array_open(ctx, buffer);
10499                 UNPACK_INFO(spec, &decoded_spec);
10500                 break;
10501               case GRN_COLUMN_VAR_SIZE :
10502                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10503                 vp->ptr = (grn_obj *)grn_ja_open(ctx, buffer);
10504                 UNPACK_INFO(spec, &decoded_spec);
10505                 break;
10506               case GRN_COLUMN_FIX_SIZE :
10507                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10508                 vp->ptr = (grn_obj *)grn_ra_open(ctx, buffer);
10509                 UNPACK_INFO(spec, &decoded_spec);
10510                 break;
10511               case GRN_COLUMN_INDEX :
10512                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10513                 {
10514                   grn_obj *table = grn_ctx_at(ctx, spec->header.domain);
10515                   vp->ptr = (grn_obj *)grn_ii_open(ctx, buffer, table);
10516                 }
10517                 UNPACK_INFO(spec, &decoded_spec);
10518                 break;
10519               case GRN_PROC :
10520                 GET_PATH(spec, &decoded_spec, buffer, s, id);
10521                 grn_plugin_register(ctx, buffer);
10522                 break;
10523               case GRN_EXPR :
10524                 {
10525                   const char *p;
10526                   uint32_t size;
10527                   uint8_t *u;
10528                   size = grn_vector_get_element(ctx,
10529                                                 &decoded_spec,
10530                                                 GRN_SERIALIZED_SPEC_INDEX_EXPR,
10531                                                 &p,
10532                                                 NULL,
10533                                                 NULL);
10534                   u = (uint8_t *)p;
10535                   vp->ptr = grn_expr_open(ctx, spec, u, u + size);
10536                 }
10537                 break;
10538               }
10539               if (!vp->ptr) {
10540                 const char *name;
10541                 uint32_t name_size = 0;
10542                 name = _grn_table_key(ctx, (grn_obj *)s, id, &name_size);
10543                 GRN_LOG(ctx, GRN_LOG_ERROR,
10544                         "grn_ctx_at: failed to open object: "
10545                         "<%u>(<%.*s>):<%u>(<%s>)",
10546                         id,
10547                         name_size, name,
10548                         spec->header.type,
10549                         grn_obj_type_to_string(spec->header.type));
10550               }
10551             }
10552             GRN_OBJ_FIN(ctx, &decoded_spec);
10553             grn_ja_unref(ctx, &iw);
10554           }
10555 #ifndef USE_NREF
10556           GRN_ATOMIC_ADD_EX(pl, -1, l);
10557 #endif /* USE_NREF */
10558           vp->done = 1;
10559           GRN_FUTEX_WAKE(&vp->ptr);
10560         } else {
10561           for (ntrial = 0; !vp->ptr; ntrial++) {
10562             if (ntrial >= 1000) {
10563               GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%d,%p,%d)!", id, vp->ptr, vp->lock);
10564               break;
10565             }
10566             GRN_FUTEX_WAIT(&vp->ptr);
10567           }
10568         }
10569         if (vp->ptr) {
10570           switch (vp->ptr->header.type) {
10571           case GRN_TABLE_HASH_KEY :
10572           case GRN_TABLE_PAT_KEY :
10573           case GRN_TABLE_DAT_KEY :
10574           case GRN_TABLE_NO_KEY :
10575           case GRN_COLUMN_FIX_SIZE :
10576           case GRN_COLUMN_VAR_SIZE :
10577           case GRN_COLUMN_INDEX :
10578             {
10579               grn_obj *space;
10580               space = ctx->impl->temporary_open_spaces.current;
10581               if (space) {
10582                 GRN_PTR_PUT(ctx, space, vp->ptr);
10583               }
10584             }
10585             break;
10586           }
10587         }
10588       }
10589       res = vp->ptr;
10590       if (res && res->header.type == GRN_PROC) {
10591         grn_plugin_ensure_registered(ctx, res);
10592       }
10593     }
10594   }
10595 exit :
10596   GRN_API_RETURN(res);
10597 }
10598 
10599 grn_bool
grn_ctx_is_opened(grn_ctx * ctx,grn_id id)10600 grn_ctx_is_opened(grn_ctx *ctx, grn_id id)
10601 {
10602   grn_bool is_opened = GRN_FALSE;
10603 
10604   if (!ctx || !ctx->impl || !id) {
10605     return GRN_FALSE;
10606   }
10607 
10608   GRN_API_ENTER;
10609   if (id & GRN_OBJ_TMP_OBJECT) {
10610     if (ctx->impl->values) {
10611       grn_obj **tmp_obj;
10612       tmp_obj = _grn_array_get_value(ctx, ctx->impl->values,
10613                                      id & ~GRN_OBJ_TMP_OBJECT);
10614       if (tmp_obj) {
10615         is_opened = GRN_TRUE;
10616       }
10617     }
10618   } else {
10619     grn_db *s = (grn_db *)ctx->impl->db;
10620     if (s) {
10621       db_value *vp;
10622       vp = grn_tiny_array_at(&s->values, id);
10623       if (vp && vp->ptr) {
10624         is_opened = GRN_TRUE;
10625       }
10626     }
10627   }
10628   GRN_API_RETURN(is_opened);
10629 }
10630 
10631 grn_obj *
grn_obj_open(grn_ctx * ctx,unsigned char type,grn_obj_flags flags,grn_id domain)10632 grn_obj_open(grn_ctx *ctx, unsigned char type, grn_obj_flags flags, grn_id domain)
10633 {
10634   grn_obj *obj = GRN_MALLOCN(grn_obj, 1);
10635   if (obj) {
10636     GRN_OBJ_INIT(obj, type, flags, domain);
10637     obj->header.impl_flags |= GRN_OBJ_ALLOCATED;
10638   }
10639   return obj;
10640 }
10641 
10642 grn_obj *
grn_obj_graft(grn_ctx * ctx,grn_obj * obj)10643 grn_obj_graft(grn_ctx *ctx, grn_obj *obj)
10644 {
10645   grn_obj *new = grn_obj_open(ctx, obj->header.type, obj->header.impl_flags, obj->header.domain);
10646   if (new) {
10647     /* todo : deep copy if (obj->header.impl_flags & GRN_OBJ_DO_SHALLOW_COPY) */
10648     new->u.b.head = obj->u.b.head;
10649     new->u.b.curr = obj->u.b.curr;
10650     new->u.b.tail = obj->u.b.tail;
10651     obj->u.b.head = NULL;
10652     obj->u.b.curr = NULL;
10653     obj->u.b.tail = NULL;
10654   }
10655   return new;
10656 }
10657 
10658 grn_rc
grn_pvector_fin(grn_ctx * ctx,grn_obj * obj)10659 grn_pvector_fin(grn_ctx *ctx, grn_obj *obj)
10660 {
10661   grn_rc rc;
10662   if (obj->header.impl_flags & GRN_OBJ_OWN) {
10663     /*
10664      * Note that GRN_OBJ_OWN should not be used outside the DB API function
10665      * because grn_obj_close is a DB API function.
10666      */
10667     unsigned int i, n_elements;
10668     n_elements = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
10669     for (i = 0; i < n_elements; i++) {
10670       grn_obj *element = GRN_PTR_VALUE_AT(obj, n_elements - i - 1);
10671       if (element) {
10672         grn_obj_close(ctx, element);
10673       }
10674     }
10675   }
10676   obj->header.type = GRN_VOID;
10677   rc = grn_bulk_fin(ctx, obj);
10678   if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) {
10679     GRN_FREE(obj);
10680   }
10681   return rc;
10682 }
10683 
10684 static void
grn_table_close_columns(grn_ctx * ctx,grn_obj * table)10685 grn_table_close_columns(grn_ctx *ctx, grn_obj *table)
10686 {
10687   grn_hash *columns;
10688   int n_columns;
10689 
10690   columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
10691                             GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
10692   if (!columns) {
10693     return;
10694   }
10695 
10696   n_columns = grn_table_columns(ctx, table, "", 0, (grn_obj *)columns);
10697   if (n_columns > 0) {
10698     grn_hash_cursor *cursor;
10699     cursor = grn_hash_cursor_open(ctx, columns, NULL, 0, NULL, 0, 0, -1, 0);
10700     if (cursor) {
10701       while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
10702         grn_id *id;
10703         grn_obj *column;
10704 
10705         grn_hash_cursor_get_key(ctx, cursor, (void **)&id);
10706         column = grn_ctx_at(ctx, *id);
10707         if (column) {
10708           grn_obj_close(ctx, column);
10709         }
10710       }
10711       grn_hash_cursor_close(ctx, cursor);
10712     }
10713   }
10714 
10715   grn_hash_close(ctx, columns);
10716 }
10717 
10718 grn_rc
grn_obj_close(grn_ctx * ctx,grn_obj * obj)10719 grn_obj_close(grn_ctx *ctx, grn_obj *obj)
10720 {
10721   grn_rc rc = GRN_INVALID_ARGUMENT;
10722   GRN_API_ENTER;
10723   if (obj) {
10724     if (grn_obj_is_table(ctx, obj) &&
10725         (DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)) {
10726       grn_table_close_columns(ctx, obj);
10727     }
10728     if (GRN_DB_OBJP(obj)) {
10729       grn_hook_entry entry;
10730       if (DB_OBJ(obj)->finalizer) {
10731         DB_OBJ(obj)->finalizer(ctx, 1, &obj, &DB_OBJ(obj)->user_data);
10732       }
10733       if (DB_OBJ(obj)->source) {
10734         GRN_FREE(DB_OBJ(obj)->source);
10735       }
10736       for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
10737         grn_hook_free(ctx, DB_OBJ(obj)->hooks[entry]);
10738       }
10739       grn_obj_delete_by_id(ctx, DB_OBJ(obj)->db, DB_OBJ(obj)->id, GRN_FALSE);
10740     }
10741     switch (obj->header.type) {
10742     case GRN_VECTOR :
10743       if (obj->u.v.body && !(obj->header.impl_flags & GRN_OBJ_REFER)) {
10744         grn_obj_close(ctx, obj->u.v.body);
10745       }
10746       if (obj->u.v.sections) { GRN_FREE(obj->u.v.sections); }
10747       if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
10748       rc = GRN_SUCCESS;
10749       break;
10750     case GRN_VOID :
10751     case GRN_BULK :
10752     case GRN_UVECTOR :
10753     case GRN_MSG :
10754       obj->header.type = GRN_VOID;
10755       rc = grn_bulk_fin(ctx, obj);
10756       if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
10757       break;
10758     case GRN_PTR :
10759       if (obj->header.impl_flags & GRN_OBJ_OWN) {
10760         if (GRN_BULK_VSIZE(obj) == sizeof(grn_obj *)) {
10761           grn_obj_close(ctx, GRN_PTR_VALUE(obj));
10762         }
10763       }
10764       obj->header.type = GRN_VOID;
10765       rc = grn_bulk_fin(ctx, obj);
10766       if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
10767       break;
10768     case GRN_PVECTOR :
10769       rc = grn_pvector_fin(ctx, obj);
10770       break;
10771     case GRN_ACCESSOR :
10772       {
10773         grn_accessor *p, *n;
10774         for (p = (grn_accessor *)obj; p; p = n) {
10775           n = p->next;
10776           GRN_FREE(p);
10777         }
10778       }
10779       rc = GRN_SUCCESS;
10780       break;
10781     case GRN_SNIP :
10782       rc = grn_snip_close(ctx, (grn_snip *)obj);
10783       break;
10784     case GRN_STRING :
10785       rc = grn_string_close(ctx, obj);
10786       break;
10787     case GRN_CURSOR_TABLE_PAT_KEY :
10788       grn_pat_cursor_close(ctx, (grn_pat_cursor *)obj);
10789       break;
10790     case GRN_CURSOR_TABLE_DAT_KEY :
10791       grn_dat_cursor_close(ctx, (grn_dat_cursor *)obj);
10792       break;
10793     case GRN_CURSOR_TABLE_HASH_KEY :
10794       grn_hash_cursor_close(ctx, (grn_hash_cursor *)obj);
10795       break;
10796     case GRN_CURSOR_TABLE_NO_KEY :
10797       grn_array_cursor_close(ctx, (grn_array_cursor *)obj);
10798       break;
10799     case GRN_CURSOR_COLUMN_INDEX :
10800       {
10801         grn_index_cursor *ic = (grn_index_cursor *)obj;
10802         if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
10803         GRN_FREE(ic);
10804       }
10805       break;
10806     case GRN_CURSOR_COLUMN_GEO_INDEX :
10807       grn_geo_cursor_close(ctx, obj);
10808       break;
10809     case GRN_CURSOR_CONFIG :
10810       grn_config_cursor_close(ctx, (grn_config_cursor *)obj);
10811       break;
10812     case GRN_TYPE :
10813       GRN_FREE(obj);
10814       rc = GRN_SUCCESS;
10815       break;
10816     case GRN_DB :
10817       rc = grn_db_close(ctx, obj);
10818       break;
10819     case GRN_TABLE_PAT_KEY :
10820       rc = grn_pat_close(ctx, (grn_pat *)obj);
10821       break;
10822     case GRN_TABLE_DAT_KEY :
10823       rc = grn_dat_close(ctx, (grn_dat *)obj);
10824       break;
10825     case GRN_TABLE_HASH_KEY :
10826       rc = grn_hash_close(ctx, (grn_hash *)obj);
10827       break;
10828     case GRN_TABLE_NO_KEY :
10829       rc = grn_array_close(ctx, (grn_array *)obj);
10830       break;
10831     case GRN_COLUMN_VAR_SIZE :
10832       rc = grn_ja_close(ctx, (grn_ja *)obj);
10833       break;
10834     case GRN_COLUMN_FIX_SIZE :
10835       rc = grn_ra_close(ctx, (grn_ra *)obj);
10836       break;
10837     case GRN_COLUMN_INDEX :
10838       rc = grn_ii_close(ctx, (grn_ii *)obj);
10839       break;
10840     case GRN_PROC :
10841       {
10842         uint32_t i;
10843         grn_proc *p = (grn_proc *)obj;
10844         /*
10845         if (obj->header.domain) {
10846           grn_hash_delete(ctx, ctx->impl->qe, &obj->header.domain, sizeof(grn_id), NULL);
10847         }
10848         */
10849         for (i = 0; i < p->nvars; i++) {
10850           grn_obj_close(ctx, &p->vars[i].value);
10851         }
10852         GRN_REALLOC(p->vars, 0);
10853         grn_obj_close(ctx, &p->name_buf);
10854         if (p->obj.range != GRN_ID_NIL) {
10855           grn_plugin_close(ctx, p->obj.range);
10856         }
10857         GRN_FREE(obj);
10858         rc = GRN_SUCCESS;
10859       }
10860       break;
10861     case GRN_EXPR :
10862       rc = grn_expr_close(ctx, obj);
10863       break;
10864     }
10865   }
10866   GRN_API_RETURN(rc);
10867 }
10868 
10869 void
grn_obj_unlink(grn_ctx * ctx,grn_obj * obj)10870 grn_obj_unlink(grn_ctx *ctx, grn_obj *obj)
10871 {
10872   if (obj &&
10873       (!GRN_DB_OBJP(obj) ||
10874        (((grn_db_obj *)obj)->id & GRN_OBJ_TMP_OBJECT) ||
10875        (((grn_db_obj *)obj)->id == GRN_ID_NIL) ||
10876        obj->header.type == GRN_DB)) {
10877     grn_obj_close(ctx, obj);
10878   } else if (GRN_DB_OBJP(obj)) {
10879 #ifdef USE_NREF
10880     grn_db_obj *dob = DB_OBJ(obj);
10881     grn_db *s = (grn_db *)dob->db;
10882     db_value *vp = grn_tiny_array_at(&s->values, dob->id);
10883     if (vp) {
10884       uint32_t l, *pl = &vp->lock;
10885       if (!vp->lock) {
10886         GRN_LOG(ctx, GRN_LOG_ERROR, "invalid unlink(%p,%d)", obj, vp->lock);
10887         return;
10888       }
10889       GRN_ATOMIC_ADD_EX(pl, -1, l);
10890       if (l == 1) {
10891         GRN_ATOMIC_ADD_EX(pl, GRN_IO_MAX_REF, l);
10892         if (l == GRN_IO_MAX_REF) {
10893 #ifdef CALL_FINALIZER
10894           grn_obj_close(ctx, obj);
10895           vp->done = 0;
10896           if (dob->finalizer) {
10897             dob->finalizer(ctx, 1, &obj, &dob->user_data);
10898             dob->finalizer = NULL;
10899             dob->user_data.ptr = NULL;
10900           }
10901 #endif /* CALL_FINALIZER */
10902         }
10903         GRN_ATOMIC_ADD_EX(pl, -GRN_IO_MAX_REF, l);
10904         GRN_FUTEX_WAKE(pl);
10905       }
10906     }
10907 #endif /* USE_NREF */
10908   }
10909 }
10910 
10911 #define VECTOR_CLEAR(ctx,obj) do {\
10912   if ((obj)->u.v.body && !((obj)->header.impl_flags & GRN_OBJ_REFER)) {\
10913     grn_obj_close((ctx), (obj)->u.v.body);\
10914   }\
10915   if ((obj)->u.v.sections) { GRN_FREE((obj)->u.v.sections); }\
10916   (obj)->header.impl_flags &= ~GRN_OBJ_DO_SHALLOW_COPY;\
10917   (obj)->u.b.head = NULL;\
10918   (obj)->u.b.curr = NULL;\
10919   (obj)->u.b.tail = NULL;\
10920 } while (0)
10921 
10922 static void
grn_obj_ensure_vector(grn_ctx * ctx,grn_obj * obj)10923 grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj)
10924 {
10925   if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
10926   obj->header.type = GRN_VECTOR;
10927   obj->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
10928 }
10929 
10930 static void
grn_obj_ensure_bulk(grn_ctx * ctx,grn_obj * obj)10931 grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj)
10932 {
10933   if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
10934   obj->header.type = GRN_BULK;
10935   obj->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
10936 }
10937 
10938 grn_rc
grn_obj_reinit(grn_ctx * ctx,grn_obj * obj,grn_id domain,unsigned char flags)10939 grn_obj_reinit(grn_ctx *ctx, grn_obj *obj, grn_id domain, unsigned char flags)
10940 {
10941   if (!GRN_OBJ_MUTABLE(obj)) {
10942     ERR(GRN_INVALID_ARGUMENT, "invalid obj assigned");
10943   } else {
10944     switch (obj->header.type) {
10945     case GRN_PTR :
10946       if (obj->header.impl_flags & GRN_OBJ_OWN) {
10947         if (GRN_BULK_VSIZE(obj) == sizeof(grn_obj *)) {
10948           grn_obj_close(ctx, GRN_PTR_VALUE(obj));
10949         }
10950         obj->header.impl_flags &= ~GRN_OBJ_OWN;
10951       }
10952       break;
10953     case GRN_PVECTOR :
10954       if (obj->header.impl_flags & GRN_OBJ_OWN) {
10955         unsigned int i, n_elements;
10956         n_elements = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
10957         for (i = 0; i < n_elements; i++) {
10958           grn_obj *element = GRN_PTR_VALUE_AT(obj, i);
10959           grn_obj_close(ctx, element);
10960         }
10961         obj->header.impl_flags &= ~GRN_OBJ_OWN;
10962       }
10963       break;
10964     default :
10965       break;
10966     }
10967 
10968     switch (domain) {
10969     case GRN_DB_VOID :
10970       if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
10971       obj->header.type = GRN_VOID;
10972       obj->header.domain = domain;
10973       GRN_BULK_REWIND(obj);
10974       break;
10975     case GRN_DB_OBJECT :
10976     case GRN_DB_BOOL :
10977     case GRN_DB_INT8 :
10978     case GRN_DB_UINT8 :
10979     case GRN_DB_INT16 :
10980     case GRN_DB_UINT16 :
10981     case GRN_DB_INT32 :
10982     case GRN_DB_UINT32 :
10983     case GRN_DB_INT64 :
10984     case GRN_DB_UINT64 :
10985     case GRN_DB_FLOAT :
10986     case GRN_DB_TIME :
10987     case GRN_DB_TOKYO_GEO_POINT :
10988     case GRN_DB_WGS84_GEO_POINT :
10989       if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
10990       obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
10991       obj->header.domain = domain;
10992       GRN_BULK_REWIND(obj);
10993       break;
10994     case GRN_DB_SHORT_TEXT :
10995     case GRN_DB_TEXT :
10996     case GRN_DB_LONG_TEXT :
10997       if (flags & GRN_OBJ_VECTOR) {
10998         if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
10999         obj->header.type = GRN_VECTOR;
11000         if (obj->u.v.body) {
11001           grn_obj_reinit(ctx, obj->u.v.body, domain, 0);
11002         }
11003         obj->u.v.n_sections = 0;
11004       } else {
11005         if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
11006         obj->header.type = GRN_BULK;
11007       }
11008       obj->header.domain = domain;
11009       GRN_BULK_REWIND(obj);
11010       break;
11011     default :
11012       {
11013         grn_obj *d = grn_ctx_at(ctx, domain);
11014         if (!d) {
11015           ERR(GRN_INVALID_ARGUMENT, "invalid domain assigned");
11016         } else {
11017           if (d->header.type == GRN_TYPE && (d->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
11018             if (flags & GRN_OBJ_VECTOR) {
11019               if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
11020               obj->header.type = GRN_VECTOR;
11021             } else {
11022               if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
11023               obj->header.type = GRN_BULK;
11024             }
11025           } else {
11026             if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
11027             obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
11028           }
11029           obj->header.domain = domain;
11030           GRN_BULK_REWIND(obj);
11031         }
11032       }
11033       break;
11034     }
11035   }
11036   return ctx->rc;
11037 }
11038 
11039 grn_rc
grn_obj_reinit_for(grn_ctx * ctx,grn_obj * obj,grn_obj * domain_obj)11040 grn_obj_reinit_for(grn_ctx *ctx, grn_obj *obj, grn_obj *domain_obj)
11041 {
11042   grn_id domain = GRN_ID_NIL;
11043   grn_obj_flags flags = 0;
11044 
11045   if (!GRN_DB_OBJP(domain_obj) && domain_obj->header.type != GRN_ACCESSOR) {
11046     grn_obj inspected;
11047     GRN_TEXT_INIT(&inspected, 0);
11048     grn_inspect_limited(ctx, &inspected, domain_obj);
11049     ERR(GRN_INVALID_ARGUMENT,
11050         "[reinit] invalid domain object: <%.*s>",
11051         (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
11052     GRN_OBJ_FIN(ctx, &inspected);
11053     return ctx->rc;
11054   }
11055 
11056   if (grn_column_is_index(ctx, domain_obj)) {
11057     domain = GRN_DB_UINT32;
11058   } else {
11059     grn_obj_get_range_info(ctx, domain_obj, &domain, &flags);
11060     if (GRN_OBJ_TABLEP(domain_obj) &&
11061         domain_obj->header.type != GRN_TABLE_NO_KEY) {
11062       domain = domain_obj->header.domain;
11063     }
11064   }
11065   return grn_obj_reinit(ctx, obj, domain, flags);
11066 }
11067 
11068 const char *
grn_obj_path(grn_ctx * ctx,grn_obj * obj)11069 grn_obj_path(grn_ctx *ctx, grn_obj *obj)
11070 {
11071   grn_io *io;
11072   const char *path = NULL;
11073   GRN_API_ENTER;
11074   if (obj->header.type == GRN_PROC) {
11075     path = grn_plugin_path(ctx, DB_OBJ(obj)->range);
11076     GRN_API_RETURN(path);
11077   }
11078   io = grn_obj_get_io(ctx, obj);
11079   if (io && !(io->flags & GRN_IO_TEMPORARY)) { path = io->path; }
11080   GRN_API_RETURN(path);
11081 }
11082 
11083 int
grn_obj_name(grn_ctx * ctx,grn_obj * obj,char * namebuf,int buf_size)11084 grn_obj_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
11085 {
11086   int len = 0;
11087   GRN_API_ENTER;
11088   if (GRN_DB_OBJP(obj)) {
11089     if (DB_OBJ(obj)->id) {
11090       grn_db *s = (grn_db *)DB_OBJ(obj)->db;
11091       grn_id id = DB_OBJ(obj)->id;
11092       if (id & GRN_OBJ_TMP_OBJECT) {
11093         if (id & GRN_OBJ_TMP_COLUMN) {
11094           grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
11095           len = grn_pat_get_key(ctx, ctx->impl->temporary_columns,
11096                                 real_id, namebuf, buf_size);
11097         }
11098       } else {
11099         len = grn_table_get_key(ctx, s->keys, id, namebuf, buf_size);
11100       }
11101     }
11102   }
11103   GRN_API_RETURN(len);
11104 }
11105 
11106 int
grn_column_name(grn_ctx * ctx,grn_obj * obj,char * namebuf,int buf_size)11107 grn_column_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
11108 {
11109   int len = 0;
11110   char buf[GRN_TABLE_MAX_KEY_SIZE];
11111   if (!obj) { return len; }
11112   GRN_API_ENTER;
11113   if (GRN_DB_OBJP(obj)) {
11114     grn_id id = DB_OBJ(obj)->id;
11115     if (id & GRN_OBJ_TMP_OBJECT) {
11116       if (id & GRN_OBJ_TMP_COLUMN) {
11117         grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
11118         len = grn_pat_get_key(ctx, ctx->impl->temporary_columns,
11119                               real_id, buf, GRN_TABLE_MAX_KEY_SIZE);
11120       }
11121     } else if (id && id < GRN_ID_MAX) {
11122       grn_db *s = (grn_db *)DB_OBJ(obj)->db;
11123       len = grn_table_get_key(ctx, s->keys, id, buf, GRN_TABLE_MAX_KEY_SIZE);
11124     }
11125     if (len) {
11126       int cl;
11127       char *p = buf, *p0 = p, *pe = p + len;
11128       for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
11129         if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
11130       }
11131       len = pe - p0;
11132       if (len && len <= buf_size) {
11133         grn_memcpy(namebuf, p0, len);
11134       }
11135     }
11136   } else if (obj->header.type == GRN_ACCESSOR) {
11137     grn_obj name;
11138     grn_accessor *a;
11139 
11140     GRN_TEXT_INIT(&name, 0);
11141 
11142 #define ADD_DELMITER() do {                             \
11143       if (GRN_TEXT_LEN(&name) > 0) {                    \
11144         GRN_TEXT_PUTC(ctx, &name, GRN_DB_DELIMITER);    \
11145       }                                                 \
11146     } while (GRN_FALSE)
11147 
11148     for (a = (grn_accessor *)obj; a; a = a->next) {
11149       switch (a->action) {
11150       case GRN_ACCESSOR_GET_ID :
11151         ADD_DELMITER();
11152         GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_ID);
11153         break;
11154       case GRN_ACCESSOR_GET_KEY :
11155         if (!a->next) {
11156           ADD_DELMITER();
11157           GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_KEY);
11158         }
11159         break;
11160       case GRN_ACCESSOR_GET_VALUE :
11161         if (!a->next) {
11162           ADD_DELMITER();
11163           GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_VALUE);
11164         }
11165         break;
11166       case GRN_ACCESSOR_GET_SCORE :
11167         ADD_DELMITER();
11168         GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_SCORE);
11169         break;
11170       case GRN_ACCESSOR_GET_NSUBRECS :
11171         ADD_DELMITER();
11172         GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_NSUBRECS);
11173         break;
11174       case GRN_ACCESSOR_GET_MAX :
11175         ADD_DELMITER();
11176         GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_MAX);
11177         break;
11178       case GRN_ACCESSOR_GET_MIN :
11179         ADD_DELMITER();
11180         GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_MIN);
11181         break;
11182       case GRN_ACCESSOR_GET_SUM :
11183         ADD_DELMITER();
11184         GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_SUM);
11185         break;
11186       case GRN_ACCESSOR_GET_AVG :
11187         ADD_DELMITER();
11188         GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_AVG);
11189         break;
11190       case GRN_ACCESSOR_GET_COLUMN_VALUE :
11191         ADD_DELMITER();
11192         {
11193           char column_name[GRN_TABLE_MAX_KEY_SIZE];
11194           int column_name_size;
11195           column_name_size = grn_column_name(ctx, a->obj,
11196                                              column_name,
11197                                              GRN_TABLE_MAX_KEY_SIZE);
11198           GRN_TEXT_PUT(ctx, &name, column_name, column_name_size);
11199         }
11200         break;
11201       case GRN_ACCESSOR_GET_DB_OBJ :
11202       case GRN_ACCESSOR_LOOKUP :
11203       case GRN_ACCESSOR_FUNCALL :
11204         break;
11205       }
11206     }
11207 #undef ADD_DELIMITER
11208 
11209     len = GRN_TEXT_LEN(&name);
11210     if (len > 0 && len <= buf_size) {
11211       grn_memcpy(namebuf, GRN_TEXT_VALUE(&name), len);
11212     }
11213 
11214     GRN_OBJ_FIN(ctx, &name);
11215   }
11216   GRN_API_RETURN(len);
11217 }
11218 
11219 grn_rc
grn_column_name_(grn_ctx * ctx,grn_obj * obj,grn_obj * buf)11220 grn_column_name_(grn_ctx *ctx, grn_obj *obj, grn_obj *buf)
11221 {
11222   if (GRN_DB_OBJP(obj)) {
11223     uint32_t len = 0;
11224     const char *p = NULL;
11225     grn_id id = DB_OBJ(obj)->id;
11226     if (id & GRN_OBJ_TMP_OBJECT) {
11227       if (id & GRN_OBJ_TMP_COLUMN) {
11228         grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
11229         p = _grn_pat_key(ctx, ctx->impl->temporary_columns, real_id, &len);
11230       }
11231     } else if (id && id < GRN_ID_MAX) {
11232       grn_db *s = (grn_db *)DB_OBJ(obj)->db;
11233       p = _grn_table_key(ctx, s->keys, id, &len);
11234     }
11235     if (len) {
11236       int cl;
11237       const char *p0 = p, *pe = p + len;
11238       for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
11239         if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
11240       }
11241       GRN_TEXT_PUT(ctx, buf, p0, pe - p0);
11242     }
11243   } else if (obj->header.type == GRN_ACCESSOR) {
11244     grn_accessor *a;
11245     for (a = (grn_accessor *)obj; a; a = a->next) {
11246       switch (a->action) {
11247       case GRN_ACCESSOR_GET_ID :
11248         GRN_TEXT_PUT(ctx, buf, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN);
11249         break;
11250       case GRN_ACCESSOR_GET_KEY :
11251         if (!a->next) {
11252           GRN_TEXT_PUT(ctx, buf, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN);
11253         }
11254         break;
11255       case GRN_ACCESSOR_GET_VALUE :
11256         if (!a->next) {
11257           GRN_TEXT_PUT(ctx, buf,
11258                        GRN_COLUMN_NAME_VALUE,
11259                        GRN_COLUMN_NAME_VALUE_LEN);
11260         }
11261         break;
11262       case GRN_ACCESSOR_GET_SCORE :
11263         GRN_TEXT_PUT(ctx, buf,
11264                      GRN_COLUMN_NAME_SCORE,
11265                      GRN_COLUMN_NAME_SCORE_LEN);
11266         break;
11267       case GRN_ACCESSOR_GET_NSUBRECS :
11268         GRN_TEXT_PUT(ctx, buf,
11269                      GRN_COLUMN_NAME_NSUBRECS,
11270                      GRN_COLUMN_NAME_NSUBRECS_LEN);
11271         break;
11272       case GRN_ACCESSOR_GET_MAX :
11273         GRN_TEXT_PUT(ctx, buf,
11274                      GRN_COLUMN_NAME_MAX,
11275                      GRN_COLUMN_NAME_MAX_LEN);
11276         break;
11277       case GRN_ACCESSOR_GET_MIN :
11278         GRN_TEXT_PUT(ctx, buf,
11279                      GRN_COLUMN_NAME_MIN,
11280                      GRN_COLUMN_NAME_MIN_LEN);
11281         break;
11282       case GRN_ACCESSOR_GET_SUM :
11283         GRN_TEXT_PUT(ctx, buf,
11284                      GRN_COLUMN_NAME_SUM,
11285                      GRN_COLUMN_NAME_SUM_LEN);
11286         break;
11287       case GRN_ACCESSOR_GET_AVG :
11288         GRN_TEXT_PUT(ctx, buf,
11289                      GRN_COLUMN_NAME_AVG,
11290                      GRN_COLUMN_NAME_AVG_LEN);
11291         break;
11292       case GRN_ACCESSOR_GET_COLUMN_VALUE :
11293         grn_column_name_(ctx, a->obj, buf);
11294         if (a->next) { GRN_TEXT_PUTC(ctx, buf, '.'); }
11295         break;
11296       case GRN_ACCESSOR_GET_DB_OBJ :
11297       case GRN_ACCESSOR_LOOKUP :
11298       case GRN_ACCESSOR_FUNCALL :
11299         break;
11300       }
11301     }
11302   }
11303   return ctx->rc;
11304 }
11305 
11306 int
grn_obj_expire(grn_ctx * ctx,grn_obj * obj,int threshold)11307 grn_obj_expire(grn_ctx *ctx, grn_obj *obj, int threshold)
11308 {
11309   GRN_API_ENTER;
11310   GRN_API_RETURN(0);
11311 }
11312 
11313 int
grn_obj_check(grn_ctx * ctx,grn_obj * obj)11314 grn_obj_check(grn_ctx *ctx, grn_obj *obj)
11315 {
11316   GRN_API_ENTER;
11317   GRN_API_RETURN(0);
11318 }
11319 
11320 grn_rc
grn_obj_lock(grn_ctx * ctx,grn_obj * obj,grn_id id,int timeout)11321 grn_obj_lock(grn_ctx *ctx, grn_obj *obj, grn_id id, int timeout)
11322 {
11323   grn_rc rc = GRN_SUCCESS;
11324   GRN_API_ENTER;
11325   rc = grn_io_lock(ctx, grn_obj_get_io(ctx, obj), timeout);
11326   if (rc == GRN_SUCCESS && obj && obj->header.type == GRN_COLUMN_INDEX) {
11327     rc = grn_io_lock(ctx, ((grn_ii *)obj)->chunk, timeout);
11328   }
11329   GRN_API_RETURN(rc);
11330 }
11331 
11332 grn_rc
grn_obj_unlock(grn_ctx * ctx,grn_obj * obj,grn_id id)11333 grn_obj_unlock(grn_ctx *ctx, grn_obj *obj, grn_id id)
11334 {
11335   GRN_API_ENTER;
11336   if (obj && obj->header.type == GRN_COLUMN_INDEX) {
11337     grn_io_unlock(((grn_ii *)obj)->chunk);
11338   }
11339   grn_io_unlock(grn_obj_get_io(ctx, obj));
11340   GRN_API_RETURN(GRN_SUCCESS);
11341 }
11342 
11343 grn_user_data *
grn_obj_user_data(grn_ctx * ctx,grn_obj * obj)11344 grn_obj_user_data(grn_ctx *ctx, grn_obj *obj)
11345 {
11346   if (!GRN_DB_OBJP(obj)) { return NULL; }
11347   return &DB_OBJ(obj)->user_data;
11348 }
11349 
11350 grn_rc
grn_obj_set_finalizer(grn_ctx * ctx,grn_obj * obj,grn_proc_func * func)11351 grn_obj_set_finalizer(grn_ctx *ctx, grn_obj *obj, grn_proc_func *func)
11352 {
11353   if (!GRN_DB_OBJP(obj)) { return GRN_INVALID_ARGUMENT; }
11354   DB_OBJ(obj)->finalizer = func;
11355   return GRN_SUCCESS;
11356 }
11357 
11358 grn_rc
grn_obj_clear_lock(grn_ctx * ctx,grn_obj * obj)11359 grn_obj_clear_lock(grn_ctx *ctx, grn_obj *obj)
11360 {
11361   GRN_API_ENTER;
11362   switch (obj->header.type) {
11363   case GRN_DB:
11364     {
11365       grn_table_cursor *cur;
11366       if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
11367         grn_id id;
11368         while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
11369           grn_obj *tbl = grn_ctx_at(ctx, id);
11370           if (tbl) {
11371             switch (tbl->header.type) {
11372             case GRN_TABLE_HASH_KEY :
11373             case GRN_TABLE_PAT_KEY:
11374             case GRN_TABLE_DAT_KEY:
11375             case GRN_TABLE_NO_KEY:
11376               grn_obj_clear_lock(ctx, tbl);
11377               break;
11378             }
11379           } else {
11380             if (ctx->rc != GRN_SUCCESS) {
11381               ERRCLR(ctx);
11382             }
11383           }
11384         }
11385         grn_table_cursor_close(ctx, cur);
11386       }
11387     }
11388     grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11389     {
11390       grn_db *db = (grn_db *)obj;
11391       if (db->specs) {
11392         grn_obj_clear_lock(ctx, (grn_obj *)(db->specs));
11393       }
11394     }
11395     break;
11396   case GRN_TABLE_NO_KEY :
11397     grn_array_queue_lock_clear(ctx, (grn_array *)obj);
11398     /* fallthru */
11399   case GRN_TABLE_HASH_KEY :
11400   case GRN_TABLE_PAT_KEY :
11401   case GRN_TABLE_DAT_KEY :
11402     {
11403       grn_hash *cols;
11404       if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
11405                                   GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
11406         if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
11407           grn_id *key;
11408           GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
11409             grn_obj *col = grn_ctx_at(ctx, *key);
11410             if (col) { grn_obj_clear_lock(ctx, col); }
11411           });
11412         }
11413         grn_hash_close(ctx, cols);
11414       }
11415       grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11416     }
11417     break;
11418   case GRN_COLUMN_FIX_SIZE:
11419   case GRN_COLUMN_VAR_SIZE:
11420     grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11421     break;
11422   case GRN_COLUMN_INDEX:
11423     grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11424     if (obj) {
11425       grn_io_clear_lock(((grn_ii *)obj)->chunk);
11426     }
11427     break;
11428   }
11429   GRN_API_RETURN(GRN_SUCCESS);
11430 }
11431 
11432 unsigned int
grn_obj_is_locked(grn_ctx * ctx,grn_obj * obj)11433 grn_obj_is_locked(grn_ctx *ctx, grn_obj *obj)
11434 {
11435   unsigned int res = 0;
11436   GRN_API_ENTER;
11437   res = grn_io_is_locked(grn_obj_get_io(ctx, obj));
11438   if (obj && obj->header.type == GRN_COLUMN_INDEX) {
11439     res += grn_io_is_locked(((grn_ii *)obj)->chunk);
11440   }
11441   GRN_API_RETURN(res);
11442 }
11443 
11444 grn_rc
grn_obj_flush(grn_ctx * ctx,grn_obj * obj)11445 grn_obj_flush(grn_ctx *ctx, grn_obj *obj)
11446 {
11447   grn_rc rc = GRN_SUCCESS;
11448 
11449   GRN_API_ENTER;
11450 
11451   switch (obj->header.type) {
11452   case GRN_DB :
11453     {
11454       grn_db *db = (grn_db *)obj;
11455       rc = grn_obj_flush(ctx, db->keys);
11456       if (rc == GRN_SUCCESS && db->specs) {
11457         rc = grn_obj_flush(ctx, (grn_obj *)(db->specs));
11458       }
11459       if (rc == GRN_SUCCESS) {
11460         rc = grn_obj_flush(ctx, (grn_obj *)(db->config));
11461       }
11462     }
11463     break;
11464   case GRN_TABLE_DAT_KEY :
11465     rc = grn_dat_flush(ctx, (grn_dat *)obj);
11466     break;
11467   case GRN_COLUMN_INDEX :
11468     rc = grn_ii_flush(ctx, (grn_ii *)obj);
11469     break;
11470   default :
11471     {
11472       grn_io *io;
11473       io = grn_obj_get_io(ctx, obj);
11474       if (io) {
11475         rc = grn_io_flush(ctx, io);
11476       }
11477     }
11478     break;
11479   }
11480 
11481   if (rc == GRN_SUCCESS &&
11482       GRN_DB_OBJP(obj) &&
11483       DB_OBJ(obj)->id != GRN_ID_NIL &&
11484       !IS_TEMP(obj)) {
11485     rc = grn_db_clean(ctx, DB_OBJ(obj)->db);
11486   }
11487 
11488   GRN_API_RETURN(rc);
11489 }
11490 
11491 grn_rc
grn_obj_flush_recursive(grn_ctx * ctx,grn_obj * obj)11492 grn_obj_flush_recursive(grn_ctx *ctx, grn_obj *obj)
11493 {
11494   grn_rc rc = GRN_SUCCESS;
11495 
11496   GRN_API_ENTER;
11497   switch (obj->header.type) {
11498   case GRN_DB :
11499     {
11500       grn_table_cursor *cursor;
11501       grn_id id;
11502 
11503       cursor = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0);
11504       if (!cursor) {
11505         GRN_API_RETURN(ctx->rc);
11506       }
11507 
11508       while ((id = grn_table_cursor_next_inline(ctx, cursor)) != GRN_ID_NIL) {
11509         grn_obj *table = grn_ctx_at(ctx, id);
11510         rc = GRN_SUCCESS;
11511         if (table) {
11512           switch (table->header.type) {
11513           case GRN_TABLE_HASH_KEY :
11514           case GRN_TABLE_PAT_KEY:
11515           case GRN_TABLE_DAT_KEY:
11516           case GRN_TABLE_NO_KEY:
11517             rc = grn_obj_flush_recursive(ctx, table);
11518             break;
11519           }
11520         } else {
11521           if (ctx->rc != GRN_SUCCESS) {
11522             ERRCLR(ctx);
11523           }
11524         }
11525         if (rc != GRN_SUCCESS) {
11526           break;
11527         }
11528       }
11529       grn_table_cursor_close(ctx, cursor);
11530     }
11531     if (rc == GRN_SUCCESS) {
11532       rc = grn_obj_flush(ctx, obj);
11533     }
11534     break;
11535   case GRN_TABLE_NO_KEY :
11536   case GRN_TABLE_HASH_KEY :
11537   case GRN_TABLE_PAT_KEY :
11538   case GRN_TABLE_DAT_KEY :
11539     {
11540       grn_hash *columns;
11541       columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
11542                                 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
11543       if (!columns) {
11544         GRN_API_RETURN(ctx->rc);
11545       }
11546 
11547       if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)columns) > 0) {
11548         grn_id *key;
11549         GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
11550           grn_obj *column = grn_ctx_at(ctx, *key);
11551           if (column) {
11552             rc = grn_obj_flush(ctx, column);
11553             if (rc != GRN_SUCCESS) {
11554               break;
11555             }
11556           }
11557         });
11558       }
11559       grn_hash_close(ctx, columns);
11560     }
11561 
11562     if (rc == GRN_SUCCESS) {
11563       rc = grn_obj_flush(ctx, obj);
11564     }
11565     break;
11566   case GRN_COLUMN_FIX_SIZE :
11567   case GRN_COLUMN_VAR_SIZE :
11568   case GRN_COLUMN_INDEX :
11569     rc = grn_obj_flush(ctx, obj);
11570     break;
11571   default :
11572     {
11573       grn_obj inspected;
11574       GRN_TEXT_INIT(&inspected, 0);
11575       grn_inspect(ctx, &inspected, obj);
11576       ERR(GRN_INVALID_ARGUMENT,
11577           "[flush] object must be DB, table or column: <%.*s>",
11578           (int)GRN_TEXT_LEN(&inspected),
11579           GRN_TEXT_VALUE(&inspected));
11580       rc = ctx->rc;
11581       GRN_OBJ_FIN(ctx, &inspected);
11582     }
11583     break;
11584   }
11585 
11586   GRN_API_RETURN(rc);
11587 }
11588 
11589 grn_obj *
grn_obj_db(grn_ctx * ctx,grn_obj * obj)11590 grn_obj_db(grn_ctx *ctx, grn_obj *obj)
11591 {
11592   grn_obj *db = NULL;
11593   GRN_API_ENTER;
11594   if (GRN_DB_OBJP(obj)) { db = DB_OBJ(obj)->db; }
11595   GRN_API_RETURN(db);
11596 }
11597 
11598 grn_id
grn_obj_id(grn_ctx * ctx,grn_obj * obj)11599 grn_obj_id(grn_ctx *ctx, grn_obj *obj)
11600 {
11601   grn_id id = GRN_ID_NIL;
11602   GRN_API_ENTER;
11603   if (GRN_DB_OBJP(obj)) {
11604     id = DB_OBJ(obj)->id;
11605   }
11606   GRN_API_RETURN(id);
11607 }
11608 
11609 int
grn_obj_defrag(grn_ctx * ctx,grn_obj * obj,int threshold)11610 grn_obj_defrag(grn_ctx *ctx, grn_obj *obj, int threshold)
11611 {
11612   int r = 0;
11613   GRN_API_ENTER;
11614   switch (obj->header.type) {
11615   case GRN_DB:
11616     {
11617       grn_table_cursor *cur;
11618       if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
11619         grn_id id;
11620         while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
11621           grn_obj *ja = grn_ctx_at(ctx, id);
11622           if (ja && ja->header.type == GRN_COLUMN_VAR_SIZE) {
11623             r += grn_ja_defrag(ctx, (grn_ja *)ja, threshold);
11624           }
11625         }
11626         grn_table_cursor_close(ctx, cur);
11627       }
11628     }
11629     break;
11630   case GRN_TABLE_HASH_KEY :
11631   case GRN_TABLE_PAT_KEY :
11632   case GRN_TABLE_DAT_KEY :
11633   case GRN_TABLE_NO_KEY :
11634     {
11635       grn_hash *cols;
11636       if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
11637                                   GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
11638         if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
11639           grn_id *key;
11640           GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
11641             grn_obj *col = grn_ctx_at(ctx, *key);
11642             if (col) {
11643               r += grn_obj_defrag(ctx, col, threshold);
11644               grn_obj_unlink(ctx, col);
11645             }
11646           });
11647         }
11648         grn_hash_close(ctx, cols);
11649       }
11650     }
11651     break;
11652   case GRN_COLUMN_VAR_SIZE:
11653     r = grn_ja_defrag(ctx, (grn_ja *)obj, threshold);
11654     break;
11655   }
11656   GRN_API_RETURN(r);
11657 }
11658 
11659 /**** sort ****/
11660 
11661 typedef struct {
11662   grn_id id;
11663   uint32_t size;
11664   const void *value;
11665 } sort_reference_entry;
11666 
11667 enum {
11668   KEY_ID = 0,
11669   KEY_BULK,
11670   KEY_INT8,
11671   KEY_INT16,
11672   KEY_INT32,
11673   KEY_INT64,
11674   KEY_UINT8,
11675   KEY_UINT16,
11676   KEY_UINT32,
11677   KEY_UINT64,
11678   KEY_FLOAT32,
11679   KEY_FLOAT64,
11680 };
11681 
11682 #define CMPNUM(type) do {\
11683   if (as) {\
11684     if (bs) {\
11685       type va = *((type *)(ap));\
11686       type vb = *((type *)(bp));\
11687       if (va != vb) { return va > vb; }\
11688     } else {\
11689       return 1;\
11690     }\
11691   } else {\
11692     if (bs) { return 0; }\
11693   }\
11694 } while (0)
11695 
11696 inline static int
compare_reference(grn_ctx * ctx,sort_reference_entry * a,sort_reference_entry * b,grn_table_sort_key * keys,int n_keys)11697 compare_reference(grn_ctx *ctx,
11698                   sort_reference_entry *a, sort_reference_entry *b,
11699                   grn_table_sort_key *keys, int n_keys)
11700 {
11701   int i;
11702   uint8_t type;
11703   uint32_t as, bs;
11704   const unsigned char *ap, *bp;
11705   for (i = 0; i < n_keys; i++, keys++) {
11706     if (i) {
11707       const char *ap_raw, *bp_raw;
11708       if (keys->flags & GRN_TABLE_SORT_DESC) {
11709         ap_raw = grn_obj_get_value_(ctx, keys->key, b->id, &as);
11710         bp_raw = grn_obj_get_value_(ctx, keys->key, a->id, &bs);
11711       } else {
11712         ap_raw = grn_obj_get_value_(ctx, keys->key, a->id, &as);
11713         bp_raw = grn_obj_get_value_(ctx, keys->key, b->id, &bs);
11714       }
11715       ap = (const unsigned char *)ap_raw;
11716       bp = (const unsigned char *)bp_raw;
11717     } else {
11718       if (keys->flags & GRN_TABLE_SORT_DESC) {
11719         ap = b->value; as = b->size;
11720         bp = a->value; bs = a->size;
11721       } else {
11722         ap = a->value; as = a->size;
11723         bp = b->value; bs = b->size;
11724       }
11725     }
11726     type = keys->offset;
11727     switch (type) {
11728     case KEY_ID :
11729       if (ap != bp) { return ap > bp; }
11730       break;
11731     case KEY_BULK :
11732       for (;; ap++, bp++, as--, bs--) {
11733         if (!as) { if (bs) { return 0; } else { break; } }
11734         if (!bs) { return 1; }
11735         if (*ap < *bp) { return 0; }
11736         if (*ap > *bp) { return 1; }
11737       }
11738       break;
11739     case KEY_INT8 :
11740       CMPNUM(int8_t);
11741       break;
11742     case KEY_INT16 :
11743       CMPNUM(int16_t);
11744       break;
11745     case KEY_INT32 :
11746       CMPNUM(int32_t);
11747       break;
11748     case KEY_INT64 :
11749       CMPNUM(int64_t);
11750       break;
11751     case KEY_UINT8 :
11752       CMPNUM(uint8_t);
11753       break;
11754     case KEY_UINT16 :
11755       CMPNUM(uint16_t);
11756       break;
11757     case KEY_UINT32 :
11758       CMPNUM(uint32_t);
11759       break;
11760     case KEY_UINT64 :
11761       CMPNUM(uint64_t);
11762       break;
11763     case KEY_FLOAT32 :
11764       if (as) {
11765         if (bs) {
11766           float va = *((float *)(ap));
11767           float vb = *((float *)(bp));
11768           if (va < vb || va > vb) { return va > vb; }
11769         } else {
11770           return 1;
11771         }
11772       } else {
11773         if (bs) { return 0; }
11774       }
11775       break;
11776     case KEY_FLOAT64 :
11777       if (as) {
11778         if (bs) {
11779           double va = *((double *)(ap));
11780           double vb = *((double *)(bp));
11781           if (va < vb || va > vb) { return va > vb; }
11782         } else {
11783           return 1;
11784         }
11785       } else {
11786         if (bs) { return 0; }
11787       }
11788       break;
11789     }
11790   }
11791   return 0;
11792 }
11793 
11794 inline static void
swap_reference(sort_reference_entry * a,sort_reference_entry * b)11795 swap_reference(sort_reference_entry *a, sort_reference_entry *b)
11796 {
11797   sort_reference_entry c_ = *a;
11798   *a = *b;
11799   *b = c_;
11800 }
11801 
11802 inline static sort_reference_entry *
part_reference(grn_ctx * ctx,sort_reference_entry * b,sort_reference_entry * e,grn_table_sort_key * keys,int n_keys)11803 part_reference(grn_ctx *ctx,
11804                sort_reference_entry *b, sort_reference_entry *e,
11805                grn_table_sort_key *keys, int n_keys)
11806 {
11807   sort_reference_entry *c;
11808   intptr_t d = e - b;
11809   if (compare_reference(ctx, b, e, keys, n_keys)) {
11810     swap_reference(b, e);
11811   }
11812   if (d < 2) { return NULL; }
11813   c = b + (d >> 1);
11814   if (compare_reference(ctx, b, c, keys, n_keys)) {
11815     swap_reference(b, c);
11816   } else {
11817     if (compare_reference(ctx, c, e, keys, n_keys)) {
11818       swap_reference(c, e);
11819     }
11820   }
11821   if (d < 3) { return NULL; }
11822   b++;
11823   swap_reference(b, c);
11824   c = b;
11825   for (;;) {
11826     do {
11827       b++;
11828     } while (compare_reference(ctx, c, b, keys, n_keys));
11829     do {
11830       e--;
11831     } while (compare_reference(ctx, e, c, keys, n_keys));
11832     if (b >= e) { break; }
11833     swap_reference(b, e);
11834   }
11835   swap_reference(c, e);
11836   return e;
11837 }
11838 
11839 static void
sort_reference(grn_ctx * ctx,sort_reference_entry * head,sort_reference_entry * tail,int from,int to,grn_table_sort_key * keys,int n_keys)11840 sort_reference(grn_ctx *ctx,
11841                sort_reference_entry *head, sort_reference_entry *tail,
11842                int from, int to,
11843                grn_table_sort_key *keys, int n_keys)
11844 {
11845   sort_reference_entry *c;
11846   if (head < tail && (c = part_reference(ctx, head, tail, keys, n_keys))) {
11847     intptr_t m = c - head + 1;
11848     if (from < m - 1) {
11849       sort_reference(ctx, head, c - 1, from, to, keys, n_keys);
11850     }
11851     if (m < to) {
11852       sort_reference(ctx, c + 1, tail, from - m, to - m, keys, n_keys);
11853     }
11854   }
11855 }
11856 
11857 static sort_reference_entry *
pack_reference(grn_ctx * ctx,grn_obj * table,sort_reference_entry * head,sort_reference_entry * tail,grn_table_sort_key * keys,int n_keys)11858 pack_reference(grn_ctx *ctx, grn_obj *table,
11859                sort_reference_entry *head, sort_reference_entry *tail,
11860                grn_table_sort_key *keys, int n_keys)
11861 {
11862   int i = 0;
11863   sort_reference_entry e, c;
11864   grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
11865   if (!tc) { return NULL; }
11866   if ((c.id = grn_table_cursor_next_inline(ctx, tc))) {
11867     c.value = grn_obj_get_value_(ctx, keys->key, c.id, &c.size);
11868     while ((e.id = grn_table_cursor_next_inline(ctx, tc))) {
11869       e.value = grn_obj_get_value_(ctx, keys->key, e.id, &e.size);
11870       if (compare_reference(ctx, &c, &e, keys, n_keys)) {
11871         *head++ = e;
11872       } else {
11873         *tail-- = e;
11874       }
11875       i++;
11876     }
11877     *head = c;
11878     i++;
11879   }
11880   grn_table_cursor_close(ctx, tc);
11881   return i > 2 ? head : NULL;
11882 }
11883 
11884 static int
grn_table_sort_reference(grn_ctx * ctx,grn_obj * table,int offset,int limit,grn_obj * result,grn_table_sort_key * keys,int n_keys)11885 grn_table_sort_reference(grn_ctx *ctx, grn_obj *table,
11886                          int offset, int limit,
11887                          grn_obj *result,
11888                          grn_table_sort_key *keys, int n_keys)
11889 {
11890   int e, n;
11891   sort_reference_entry *array, *ep;
11892   e = offset + limit;
11893   n = grn_table_size(ctx, table);
11894   if (!(array = GRN_MALLOC(sizeof(sort_reference_entry) * n))) {
11895     return 0;
11896   }
11897   if ((ep = pack_reference(ctx, table, array, array + n - 1, keys, n_keys))) {
11898     intptr_t m = ep - array + 1;
11899     if (offset < m - 1) {
11900       sort_reference(ctx, array, ep - 1, offset, e, keys, n_keys);
11901     }
11902     if (m < e) {
11903       sort_reference(ctx, ep + 1, array + n - 1, offset - m, e - m, keys, n_keys);
11904     }
11905   }
11906   {
11907     int i;
11908     grn_id *v;
11909     for (i = 0, ep = array + offset; i < limit && ep < array + n; i++, ep++) {
11910       if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
11911       *v = ep->id;
11912     }
11913     GRN_FREE(array);
11914     return i;
11915   }
11916 }
11917 
11918 
11919 typedef struct {
11920   grn_id id;
11921   grn_obj value;
11922 } sort_value_entry;
11923 
11924 inline static int
compare_value(grn_ctx * ctx,sort_value_entry * a,sort_value_entry * b,grn_table_sort_key * keys,int n_keys,grn_obj * a_buffer,grn_obj * b_buffer)11925 compare_value(grn_ctx *ctx,
11926               sort_value_entry *a, sort_value_entry *b,
11927               grn_table_sort_key *keys, int n_keys,
11928               grn_obj *a_buffer, grn_obj *b_buffer)
11929 {
11930   int i;
11931   uint8_t type;
11932   uint32_t as, bs;
11933   const unsigned char *ap, *bp;
11934   for (i = 0; i < n_keys; i++, keys++) {
11935     if (i) {
11936       GRN_BULK_REWIND(a_buffer);
11937       GRN_BULK_REWIND(b_buffer);
11938       if (keys->flags & GRN_TABLE_SORT_DESC) {
11939         grn_obj_get_value(ctx, keys->key, b->id, a_buffer);
11940         grn_obj_get_value(ctx, keys->key, a->id, b_buffer);
11941       } else {
11942         grn_obj_get_value(ctx, keys->key, a->id, a_buffer);
11943         grn_obj_get_value(ctx, keys->key, b->id, b_buffer);
11944       }
11945       ap = (const unsigned char *)GRN_BULK_HEAD(a_buffer);
11946       as = GRN_BULK_VSIZE(a_buffer);
11947       bp = (const unsigned char *)GRN_BULK_HEAD(b_buffer);
11948       bs = GRN_BULK_VSIZE(b_buffer);
11949     } else {
11950       if (keys->flags & GRN_TABLE_SORT_DESC) {
11951         ap = (const unsigned char *)GRN_BULK_HEAD(&b->value);
11952         as = GRN_BULK_VSIZE(&b->value);
11953         bp = (const unsigned char *)GRN_BULK_HEAD(&a->value);
11954         bs = GRN_BULK_VSIZE(&a->value);
11955       } else {
11956         ap = (const unsigned char *)GRN_BULK_HEAD(&a->value);
11957         as = GRN_BULK_VSIZE(&a->value);
11958         bp = (const unsigned char *)GRN_BULK_HEAD(&b->value);
11959         bs = GRN_BULK_VSIZE(&b->value);
11960       }
11961     }
11962     type = keys->offset;
11963     switch (type) {
11964     case KEY_ID :
11965       if (ap != bp) { return ap > bp; }
11966       break;
11967     case KEY_BULK :
11968       for (;; ap++, bp++, as--, bs--) {
11969         if (!as) { if (bs) { return 0; } else { break; } }
11970         if (!bs) { return 1; }
11971         if (*ap < *bp) { return 0; }
11972         if (*ap > *bp) { return 1; }
11973       }
11974       break;
11975     case KEY_INT8 :
11976       CMPNUM(int8_t);
11977       break;
11978     case KEY_INT16 :
11979       CMPNUM(int16_t);
11980       break;
11981     case KEY_INT32 :
11982       CMPNUM(int32_t);
11983       break;
11984     case KEY_INT64 :
11985       CMPNUM(int64_t);
11986       break;
11987     case KEY_UINT8 :
11988       CMPNUM(uint8_t);
11989       break;
11990     case KEY_UINT16 :
11991       CMPNUM(uint16_t);
11992       break;
11993     case KEY_UINT32 :
11994       CMPNUM(uint32_t);
11995       break;
11996     case KEY_UINT64 :
11997       CMPNUM(uint64_t);
11998       break;
11999     case KEY_FLOAT32 :
12000       if (as) {
12001         if (bs) {
12002           float va = *((float *)(ap));
12003           float vb = *((float *)(bp));
12004           if (va < vb || va > vb) { return va > vb; }
12005         } else {
12006           return 1;
12007         }
12008       } else {
12009         if (bs) { return 0; }
12010       }
12011       break;
12012     case KEY_FLOAT64 :
12013       if (as) {
12014         if (bs) {
12015           double va = *((double *)(ap));
12016           double vb = *((double *)(bp));
12017           if (va < vb || va > vb) { return va > vb; }
12018         } else {
12019           return 1;
12020         }
12021       } else {
12022         if (bs) { return 0; }
12023       }
12024       break;
12025     }
12026   }
12027   return 0;
12028 }
12029 
12030 inline static void
swap_value(sort_value_entry * a,sort_value_entry * b)12031 swap_value(sort_value_entry *a, sort_value_entry *b)
12032 {
12033   sort_value_entry c_ = *a;
12034   *a = *b;
12035   *b = c_;
12036 }
12037 
12038 inline static sort_value_entry *
part_value(grn_ctx * ctx,sort_value_entry * b,sort_value_entry * e,grn_table_sort_key * keys,int n_keys,grn_obj * a_buffer,grn_obj * b_buffer)12039 part_value(grn_ctx *ctx,
12040            sort_value_entry *b, sort_value_entry *e,
12041            grn_table_sort_key *keys, int n_keys,
12042            grn_obj *a_buffer, grn_obj *b_buffer)
12043 {
12044   sort_value_entry *c;
12045   intptr_t d = e - b;
12046   if (compare_value(ctx, b, e, keys, n_keys, a_buffer, b_buffer)) {
12047     swap_value(b, e);
12048   }
12049   if (d < 2) { return NULL; }
12050   c = b + (d >> 1);
12051   if (compare_value(ctx, b, c, keys, n_keys, a_buffer, b_buffer)) {
12052     swap_value(b, c);
12053   } else {
12054     if (compare_value(ctx, c, e, keys, n_keys, a_buffer, b_buffer)) {
12055       swap_value(c, e);
12056     }
12057   }
12058   if (d < 3) { return NULL; }
12059   b++;
12060   swap_value(b, c);
12061   c = b;
12062   for (;;) {
12063     do {
12064       b++;
12065     } while (compare_value(ctx, c, b, keys, n_keys, a_buffer, b_buffer));
12066     do {
12067       e--;
12068     } while (compare_value(ctx, e, c, keys, n_keys, a_buffer, b_buffer));
12069     if (b >= e) { break; }
12070     swap_value(b, e);
12071   }
12072   swap_value(c, e);
12073   return e;
12074 }
12075 
12076 static void
sort_value(grn_ctx * ctx,sort_value_entry * head,sort_value_entry * tail,int from,int to,grn_table_sort_key * keys,int n_keys,grn_obj * a_buffer,grn_obj * b_buffer)12077 sort_value(grn_ctx *ctx,
12078            sort_value_entry *head, sort_value_entry *tail,
12079            int from, int to,
12080            grn_table_sort_key *keys, int n_keys,
12081            grn_obj *a_buffer, grn_obj *b_buffer)
12082 {
12083   sort_value_entry *c;
12084   if (head < tail && (c = part_value(ctx, head, tail, keys, n_keys,
12085                                      a_buffer, b_buffer))) {
12086     intptr_t m = c - head + 1;
12087     if (from < m - 1) {
12088       sort_value(ctx, head, c - 1, from, to, keys, n_keys, a_buffer, b_buffer);
12089     }
12090     if (m < to) {
12091       sort_value(ctx, c + 1, tail, from - m, to - m, keys, n_keys,
12092                  a_buffer, b_buffer);
12093     }
12094   }
12095 }
12096 
12097 static sort_value_entry *
pack_value(grn_ctx * ctx,grn_obj * table,sort_value_entry * head,sort_value_entry * tail,grn_table_sort_key * keys,int n_keys,grn_obj * a_buffer,grn_obj * b_buffer)12098 pack_value(grn_ctx *ctx, grn_obj *table,
12099            sort_value_entry *head, sort_value_entry *tail,
12100            grn_table_sort_key *keys, int n_keys,
12101            grn_obj *a_buffer, grn_obj *b_buffer)
12102 {
12103   int i = 0;
12104   sort_value_entry e, c;
12105   grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
12106   if (!tc) { return NULL; }
12107   if ((c.id = grn_table_cursor_next_inline(ctx, tc))) {
12108     GRN_TEXT_INIT(&c.value, 0);
12109     grn_obj_get_value(ctx, keys->key, c.id, &c.value);
12110     while ((e.id = grn_table_cursor_next_inline(ctx, tc))) {
12111       GRN_TEXT_INIT(&e.value, 0);
12112       grn_obj_get_value(ctx, keys->key, e.id, &e.value);
12113       if (compare_value(ctx, &c, &e, keys, n_keys, a_buffer, b_buffer)) {
12114         *head++ = e;
12115       } else {
12116         *tail-- = e;
12117       }
12118       i++;
12119     }
12120     *head = c;
12121     i++;
12122   }
12123   grn_table_cursor_close(ctx, tc);
12124   return i > 2 ? head : NULL;
12125 }
12126 
12127 static int
grn_table_sort_value(grn_ctx * ctx,grn_obj * table,int offset,int limit,grn_obj * result,grn_table_sort_key * keys,int n_keys)12128 grn_table_sort_value(grn_ctx *ctx, grn_obj *table,
12129                      int offset, int limit,
12130                      grn_obj *result,
12131                      grn_table_sort_key *keys, int n_keys)
12132 {
12133   int e, n;
12134   sort_value_entry *array, *ep;
12135   e = offset + limit;
12136   n = grn_table_size(ctx, table);
12137   if (!(array = GRN_MALLOC(sizeof(sort_value_entry) * n))) {
12138     return 0;
12139   }
12140   {
12141     grn_obj a_buffer;
12142     grn_obj b_buffer;
12143     GRN_TEXT_INIT(&a_buffer, 0);
12144     GRN_TEXT_INIT(&b_buffer, 0);
12145     if ((ep = pack_value(ctx, table, array, array + n - 1, keys, n_keys,
12146                          &a_buffer, &b_buffer))) {
12147       intptr_t m = ep - array + 1;
12148       if (offset < m - 1) {
12149         sort_value(ctx, array, ep - 1, offset, e, keys, n_keys,
12150                    &a_buffer, &b_buffer);
12151       }
12152       if (m < e) {
12153         sort_value(ctx, ep + 1, array + n - 1, offset - m, e - m, keys, n_keys,
12154                    &a_buffer, &b_buffer);
12155       }
12156     }
12157     GRN_OBJ_FIN(ctx, &a_buffer);
12158     GRN_OBJ_FIN(ctx, &b_buffer);
12159   }
12160   {
12161     int i;
12162     grn_id *v;
12163     for (i = 0, ep = array + offset; i < limit && ep < array + n; i++, ep++) {
12164       if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
12165       *v = ep->id;
12166     }
12167     GRN_FREE(array);
12168     return i;
12169   }
12170 }
12171 
12172 static grn_bool
is_compressed_column(grn_ctx * ctx,grn_obj * obj)12173 is_compressed_column(grn_ctx *ctx, grn_obj *obj)
12174 {
12175   grn_obj *target_obj;
12176 
12177   if (!obj) {
12178     return GRN_FALSE;
12179   }
12180 
12181   if (obj->header.type == GRN_ACCESSOR) {
12182     grn_accessor *a = (grn_accessor *)obj;
12183     while (a->next) {
12184       a = a->next;
12185     }
12186     target_obj = a->obj;
12187   } else {
12188     target_obj = obj;
12189   }
12190 
12191   if (target_obj->header.type != GRN_COLUMN_VAR_SIZE) {
12192     return GRN_FALSE;
12193   }
12194 
12195   switch (target_obj->header.flags & GRN_OBJ_COMPRESS_MASK) {
12196   case GRN_OBJ_COMPRESS_ZLIB :
12197   case GRN_OBJ_COMPRESS_LZ4 :
12198   case GRN_OBJ_COMPRESS_ZSTD :
12199     return GRN_TRUE;
12200   default :
12201     return GRN_FALSE;
12202   }
12203 }
12204 
12205 static grn_bool
is_sub_record_accessor(grn_ctx * ctx,grn_obj * obj)12206 is_sub_record_accessor(grn_ctx *ctx, grn_obj *obj)
12207 {
12208   grn_accessor *accessor;
12209 
12210   if (!obj) {
12211     return GRN_FALSE;
12212   }
12213 
12214   if (obj->header.type != GRN_ACCESSOR) {
12215     return GRN_FALSE;
12216   }
12217 
12218   for (accessor = (grn_accessor *)obj; accessor; accessor = accessor->next) {
12219     switch (accessor->action) {
12220     case GRN_ACCESSOR_GET_VALUE :
12221       if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(accessor->obj)) {
12222         return GRN_TRUE;
12223       }
12224       break;
12225     default :
12226       break;
12227     }
12228   }
12229 
12230   return GRN_FALSE;
12231 }
12232 
12233 static grn_bool
is_encoded_pat_key_accessor(grn_ctx * ctx,grn_obj * obj)12234 is_encoded_pat_key_accessor(grn_ctx *ctx, grn_obj *obj)
12235 {
12236   grn_accessor *accessor;
12237 
12238   if (!grn_obj_is_accessor(ctx, obj)) {
12239     return GRN_FALSE;
12240   }
12241 
12242   accessor = (grn_accessor *)obj;
12243   while (accessor->next) {
12244     accessor = accessor->next;
12245   }
12246 
12247   if (accessor->action != GRN_ACCESSOR_GET_KEY) {
12248     return GRN_FALSE;
12249   }
12250 
12251   if (accessor->obj->header.type != GRN_TABLE_PAT_KEY) {
12252     return GRN_FALSE;
12253   }
12254 
12255   return grn_pat_is_key_encoded(ctx, (grn_pat *)(accessor->obj));
12256 }
12257 
12258 static int
range_is_idp(grn_obj * obj)12259 range_is_idp(grn_obj *obj)
12260 {
12261   if (obj && obj->header.type == GRN_ACCESSOR) {
12262     grn_accessor *a;
12263     for (a = (grn_accessor *)obj; a; a = a->next) {
12264       if (a->action == GRN_ACCESSOR_GET_ID) { return 1; }
12265     }
12266   }
12267   return 0;
12268 }
12269 
12270 int
grn_table_sort(grn_ctx * ctx,grn_obj * table,int offset,int limit,grn_obj * result,grn_table_sort_key * keys,int n_keys)12271 grn_table_sort(grn_ctx *ctx, grn_obj *table, int offset, int limit,
12272                grn_obj *result, grn_table_sort_key *keys, int n_keys)
12273 {
12274   grn_rc rc;
12275   grn_obj *index;
12276   int n, e, i = 0;
12277   GRN_API_ENTER;
12278   if (!n_keys || !keys) {
12279     WARN(GRN_INVALID_ARGUMENT, "keys is null");
12280     goto exit;
12281   }
12282   if (!table) {
12283     WARN(GRN_INVALID_ARGUMENT, "table is null");
12284     goto exit;
12285   }
12286   if (!(result && result->header.type == GRN_TABLE_NO_KEY)) {
12287     WARN(GRN_INVALID_ARGUMENT, "result is not a array");
12288     goto exit;
12289   }
12290   n = grn_table_size(ctx, table);
12291   if ((rc = grn_normalize_offset_and_limit(ctx, n, &offset, &limit))) {
12292     ERR(rc, "grn_normalize_offset_and_limit failed");
12293     goto exit;
12294   } else {
12295     e = offset + limit;
12296   }
12297   if (keys->flags & GRN_TABLE_SORT_GEO) {
12298     if (n_keys == 2) {
12299       i = grn_geo_table_sort(ctx, table, offset, limit, result,
12300                              keys[0].key, keys[1].key);
12301     } else {
12302       i = 0;
12303     }
12304     goto exit;
12305   }
12306   if (n_keys == 1 && !GRN_ACCESSORP(keys->key) &&
12307       grn_column_index(ctx, keys->key, GRN_OP_LESS, &index, 1, NULL)) {
12308     grn_id tid;
12309     grn_pat *lexicon = (grn_pat *)grn_ctx_at(ctx, index->header.domain);
12310     grn_pat_cursor *pc = grn_pat_cursor_open(ctx, lexicon, NULL, 0, NULL, 0,
12311                                              0 /* offset : can be used in unique index */,
12312                                              -1 /* limit : can be used in unique index */,
12313                                              (keys->flags & GRN_TABLE_SORT_DESC)
12314                                              ? GRN_CURSOR_DESCENDING
12315                                              : GRN_CURSOR_ASCENDING);
12316     if (pc) {
12317       while (i < e && (tid = grn_pat_cursor_next(ctx, pc))) {
12318         grn_ii_cursor *ic = grn_ii_cursor_open(ctx, (grn_ii *)index, tid, 0, 0, 1, 0);
12319         if (ic) {
12320           grn_posting *posting;
12321           while (i < e && (posting = grn_ii_cursor_next(ctx, ic))) {
12322             if (offset <= i) {
12323               grn_id *v;
12324               if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
12325               *v = posting->rid;
12326             }
12327             i++;
12328           }
12329           grn_ii_cursor_close(ctx, ic);
12330         }
12331       }
12332       grn_pat_cursor_close(ctx, pc);
12333     }
12334   } else {
12335     int j;
12336     grn_bool have_compressed_column = GRN_FALSE;
12337     grn_bool have_sub_record_accessor = GRN_FALSE;
12338     grn_bool have_encoded_pat_key_accessor = GRN_FALSE;
12339     grn_bool have_index_value_get = GRN_FALSE;
12340     grn_table_sort_key *kp;
12341     for (kp = keys, j = n_keys; j; kp++, j--) {
12342       if (is_compressed_column(ctx, kp->key)) {
12343         have_compressed_column = GRN_TRUE;
12344       }
12345       if (is_sub_record_accessor(ctx, kp->key)) {
12346         have_sub_record_accessor = GRN_TRUE;
12347       }
12348       if (is_encoded_pat_key_accessor(ctx, kp->key)) {
12349         have_encoded_pat_key_accessor = GRN_TRUE;
12350       }
12351       if (range_is_idp(kp->key)) {
12352         kp->offset = KEY_ID;
12353       } else {
12354         grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, kp->key));
12355         if (range->header.type == GRN_TYPE) {
12356           if (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
12357             kp->offset = KEY_BULK;
12358           } else {
12359             uint8_t key_type = range->header.flags & GRN_OBJ_KEY_MASK;
12360             switch (key_type) {
12361             case GRN_OBJ_KEY_UINT :
12362             case GRN_OBJ_KEY_GEO_POINT :
12363               switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
12364               case 1 :
12365                 kp->offset = KEY_UINT8;
12366                 break;
12367               case 2 :
12368                 kp->offset = KEY_UINT16;
12369                 break;
12370               case 4 :
12371                 kp->offset = KEY_UINT32;
12372                 break;
12373               case 8 :
12374                 kp->offset = KEY_UINT64;
12375                 break;
12376               default :
12377                 ERR(GRN_INVALID_ARGUMENT, "unsupported uint value");
12378                 goto exit;
12379               }
12380               break;
12381             case GRN_OBJ_KEY_INT :
12382               switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
12383               case 1 :
12384                 kp->offset = KEY_INT8;
12385                 break;
12386               case 2 :
12387                 kp->offset = KEY_INT16;
12388                 break;
12389               case 4 :
12390                 kp->offset = KEY_INT32;
12391                 break;
12392               case 8 :
12393                 kp->offset = KEY_INT64;
12394                 break;
12395               default :
12396                 ERR(GRN_INVALID_ARGUMENT, "unsupported int value");
12397                 goto exit;
12398               }
12399               break;
12400             case GRN_OBJ_KEY_FLOAT :
12401               switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
12402               case 4 :
12403                 kp->offset = KEY_FLOAT32;
12404                 break;
12405               case 8 :
12406                 kp->offset = KEY_FLOAT64;
12407                 break;
12408               default :
12409                 ERR(GRN_INVALID_ARGUMENT, "unsupported float value");
12410                 goto exit;
12411               }
12412               break;
12413             }
12414           }
12415         } else {
12416           if (kp->key->header.type == GRN_COLUMN_INDEX) {
12417             have_index_value_get = GRN_TRUE;
12418           }
12419           kp->offset = KEY_UINT32;
12420         }
12421       }
12422     }
12423     if (have_compressed_column ||
12424         have_sub_record_accessor ||
12425         have_encoded_pat_key_accessor ||
12426         have_index_value_get) {
12427       i = grn_table_sort_value(ctx, table, offset, limit, result,
12428                                keys, n_keys);
12429     } else {
12430       i = grn_table_sort_reference(ctx, table, offset, limit, result,
12431                                    keys, n_keys);
12432     }
12433   }
12434 exit :
12435   GRN_API_RETURN(i);
12436 }
12437 
12438 static grn_obj *
deftype(grn_ctx * ctx,const char * name,grn_obj_flags flags,unsigned int size)12439 deftype(grn_ctx *ctx, const char *name,
12440         grn_obj_flags flags,  unsigned int size)
12441 {
12442   grn_obj *o = grn_ctx_get(ctx, name, strlen(name));
12443   if (!o) { o = grn_type_create(ctx, name, strlen(name), flags, size); }
12444   return o;
12445 }
12446 
12447 grn_rc
grn_db_init_builtin_types(grn_ctx * ctx)12448 grn_db_init_builtin_types(grn_ctx *ctx)
12449 {
12450   grn_id id;
12451   grn_obj *obj, *db = ctx->impl->db;
12452   char buf[] = "Sys00";
12453   grn_obj_register(ctx, db, buf, 5);
12454   obj = deftype(ctx, "Object",
12455                 GRN_OBJ_KEY_UINT, sizeof(uint64_t));
12456   if (!obj || DB_OBJ(obj)->id != GRN_DB_OBJECT) { return GRN_FILE_CORRUPT; }
12457   obj = deftype(ctx, "Bool",
12458                 GRN_OBJ_KEY_UINT, sizeof(uint8_t));
12459   if (!obj || DB_OBJ(obj)->id != GRN_DB_BOOL) { return GRN_FILE_CORRUPT; }
12460   obj = deftype(ctx, "Int8",
12461                 GRN_OBJ_KEY_INT, sizeof(int8_t));
12462   if (!obj || DB_OBJ(obj)->id != GRN_DB_INT8) { return GRN_FILE_CORRUPT; }
12463   obj = deftype(ctx, "UInt8",
12464                 GRN_OBJ_KEY_UINT, sizeof(uint8_t));
12465   if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT8) { return GRN_FILE_CORRUPT; }
12466   obj = deftype(ctx, "Int16",
12467                 GRN_OBJ_KEY_INT, sizeof(int16_t));
12468   if (!obj || DB_OBJ(obj)->id != GRN_DB_INT16) { return GRN_FILE_CORRUPT; }
12469   obj = deftype(ctx, "UInt16",
12470                 GRN_OBJ_KEY_UINT, sizeof(uint16_t));
12471   if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT16) { return GRN_FILE_CORRUPT; }
12472   obj = deftype(ctx, "Int32",
12473                 GRN_OBJ_KEY_INT, sizeof(int32_t));
12474   if (!obj || DB_OBJ(obj)->id != GRN_DB_INT32) { return GRN_FILE_CORRUPT; }
12475   obj = deftype(ctx, "UInt32",
12476                 GRN_OBJ_KEY_UINT, sizeof(uint32_t));
12477   if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT32) { return GRN_FILE_CORRUPT; }
12478   obj = deftype(ctx, "Int64",
12479                 GRN_OBJ_KEY_INT, sizeof(int64_t));
12480   if (!obj || DB_OBJ(obj)->id != GRN_DB_INT64) { return GRN_FILE_CORRUPT; }
12481   obj = deftype(ctx, "UInt64",
12482                 GRN_OBJ_KEY_UINT, sizeof(uint64_t));
12483   if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT64) { return GRN_FILE_CORRUPT; }
12484   obj = deftype(ctx, "Float",
12485                 GRN_OBJ_KEY_FLOAT, sizeof(double));
12486   if (!obj || DB_OBJ(obj)->id != GRN_DB_FLOAT) { return GRN_FILE_CORRUPT; }
12487   obj = deftype(ctx, "Time",
12488                 GRN_OBJ_KEY_INT, sizeof(int64_t));
12489   if (!obj || DB_OBJ(obj)->id != GRN_DB_TIME) { return GRN_FILE_CORRUPT; }
12490   obj = deftype(ctx, "ShortText",
12491                 GRN_OBJ_KEY_VAR_SIZE, GRN_TABLE_MAX_KEY_SIZE);
12492   if (!obj || DB_OBJ(obj)->id != GRN_DB_SHORT_TEXT) { return GRN_FILE_CORRUPT; }
12493   obj = deftype(ctx, "Text",
12494                 GRN_OBJ_KEY_VAR_SIZE, 1 << 16);
12495   if (!obj || DB_OBJ(obj)->id != GRN_DB_TEXT) { return GRN_FILE_CORRUPT; }
12496   obj = deftype(ctx, "LongText",
12497                 GRN_OBJ_KEY_VAR_SIZE, 1 << 31);
12498   if (!obj || DB_OBJ(obj)->id != GRN_DB_LONG_TEXT) { return GRN_FILE_CORRUPT; }
12499   obj = deftype(ctx, "TokyoGeoPoint",
12500                 GRN_OBJ_KEY_GEO_POINT, sizeof(grn_geo_point));
12501   if (!obj || DB_OBJ(obj)->id != GRN_DB_TOKYO_GEO_POINT) { return GRN_FILE_CORRUPT; }
12502   obj = deftype(ctx, "WGS84GeoPoint",
12503                 GRN_OBJ_KEY_GEO_POINT, sizeof(grn_geo_point));
12504   if (!obj || DB_OBJ(obj)->id != GRN_DB_WGS84_GEO_POINT) { return GRN_FILE_CORRUPT; }
12505   for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_DB_MECAB; id++) {
12506     grn_itoh(id, buf + 3, 2);
12507     grn_obj_register(ctx, db, buf, 5);
12508   }
12509 #ifdef GRN_WITH_MECAB
12510   if (grn_db_init_mecab_tokenizer(ctx)) {
12511     ERRCLR(ctx);
12512 #endif
12513     grn_obj_register(ctx, db, "TokenMecab", 10);
12514 #ifdef GRN_WITH_MECAB
12515   }
12516 #endif
12517   grn_db_init_builtin_tokenizers(ctx);
12518   grn_db_init_builtin_normalizers(ctx);
12519   grn_db_init_builtin_scorers(ctx);
12520   for (id = grn_db_curr_id(ctx, db) + 1; id < 128; id++) {
12521     grn_itoh(id, buf + 3, 2);
12522     grn_obj_register(ctx, db, buf, 5);
12523   }
12524   grn_db_init_builtin_commands(ctx);
12525   grn_db_init_builtin_window_functions(ctx);
12526   for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_N_RESERVED_TYPES; id++) {
12527     grn_itoh(id, buf + 3, 2);
12528     grn_obj_register(ctx, db, buf, 5);
12529   }
12530   return ctx->rc;
12531 }
12532 
12533 #define MULTI_COLUMN_INDEXP(i) (DB_OBJ(i)->source_size > sizeof(grn_id))
12534 
12535 static grn_obj *
grn_index_column_get_tokenizer(grn_ctx * ctx,grn_obj * index_column)12536 grn_index_column_get_tokenizer(grn_ctx *ctx, grn_obj *index_column)
12537 {
12538   grn_obj *tokenizer;
12539   grn_obj *lexicon;
12540 
12541   lexicon = grn_ctx_at(ctx, index_column->header.domain);
12542   if (!lexicon) {
12543     return NULL;
12544   }
12545 
12546   grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
12547   return tokenizer;
12548 }
12549 
12550 static grn_bool
is_full_text_searchable_index(grn_ctx * ctx,grn_obj * index_column)12551 is_full_text_searchable_index(grn_ctx *ctx, grn_obj *index_column)
12552 {
12553   grn_obj *tokenizer;
12554 
12555   tokenizer = grn_index_column_get_tokenizer(ctx, index_column);
12556   return tokenizer != NULL;
12557 }
12558 
12559 static int
grn_column_find_index_data_column_equal(grn_ctx * ctx,grn_obj * obj,grn_operator op,grn_index_datum * index_data,unsigned int n_index_data,grn_obj ** index_buf,int buf_size,int * section_buf)12560 grn_column_find_index_data_column_equal(grn_ctx *ctx, grn_obj *obj,
12561                                         grn_operator op,
12562                                         grn_index_datum *index_data,
12563                                         unsigned int n_index_data,
12564                                         grn_obj **index_buf, int buf_size,
12565                                         int *section_buf)
12566 {
12567   int n = 0;
12568   grn_obj **ip = index_buf;
12569   grn_hook *hooks;
12570 
12571   for (hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
12572     grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12573     grn_obj *target = grn_ctx_at(ctx, data->target);
12574     int section;
12575     if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12576     if (obj->header.type != GRN_COLUMN_FIX_SIZE) {
12577       if (is_full_text_searchable_index(ctx, target)) { continue; }
12578     }
12579     section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12580     if (section_buf) { *section_buf = section; }
12581     if (n < buf_size) {
12582       *ip++ = target;
12583     }
12584     if (n < n_index_data) {
12585       index_data[n].index = target;
12586       index_data[n].section = section;
12587     }
12588     n++;
12589   }
12590 
12591   return n;
12592 }
12593 
12594 static grn_bool
is_valid_regexp_index(grn_ctx * ctx,grn_obj * index_column)12595 is_valid_regexp_index(grn_ctx *ctx, grn_obj *index_column)
12596 {
12597   grn_obj *tokenizer;
12598 
12599   tokenizer = grn_index_column_get_tokenizer(ctx, index_column);
12600   /* TODO: Restrict to TokenRegexp? */
12601   return tokenizer != NULL;
12602 }
12603 
12604 static int
grn_column_find_index_data_column_match(grn_ctx * ctx,grn_obj * obj,grn_operator op,grn_index_datum * index_data,unsigned int n_index_data,grn_obj ** index_buf,int buf_size,int * section_buf)12605 grn_column_find_index_data_column_match(grn_ctx *ctx, grn_obj *obj,
12606                                         grn_operator op,
12607                                         grn_index_datum *index_data,
12608                                         unsigned int n_index_data,
12609                                         grn_obj **index_buf, int buf_size,
12610                                         int *section_buf)
12611 {
12612   int n = 0;
12613   grn_obj **ip = index_buf;
12614   grn_hook_entry hook_entry;
12615   grn_hook *hooks;
12616   grn_bool prefer_full_text_search_index = GRN_FALSE;
12617 
12618   switch (obj->header.type) {
12619   case GRN_TABLE_HASH_KEY :
12620   case GRN_TABLE_PAT_KEY :
12621   case GRN_TABLE_DAT_KEY :
12622   case GRN_TABLE_NO_KEY :
12623     hook_entry = GRN_HOOK_INSERT;
12624     break;
12625   default :
12626     hook_entry = GRN_HOOK_SET;
12627     break;
12628   }
12629 
12630   if (op != GRN_OP_REGEXP && !grn_column_is_vector(ctx, obj)) {
12631     prefer_full_text_search_index = GRN_TRUE;
12632   }
12633 
12634   if (prefer_full_text_search_index) {
12635     for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
12636       grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12637       grn_obj *target = grn_ctx_at(ctx, data->target);
12638       int section;
12639       if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12640       if (!is_full_text_searchable_index(ctx, target)) { continue; }
12641       section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12642       if (section_buf) { *section_buf = section; }
12643       if (n < buf_size) {
12644         *ip++ = target;
12645       }
12646       if (n < n_index_data) {
12647         index_data[n].index = target;
12648         index_data[n].section = section;
12649       }
12650       n++;
12651     }
12652   }
12653 
12654   for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
12655     grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12656     grn_obj *target = grn_ctx_at(ctx, data->target);
12657     int section;
12658 
12659     if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12660     if (op == GRN_OP_REGEXP && !is_valid_regexp_index(ctx, target)) {
12661       continue;
12662     }
12663 
12664     if (prefer_full_text_search_index) {
12665       if (is_full_text_searchable_index(ctx, target)) { continue; }
12666     }
12667 
12668     section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12669     if (section_buf) { *section_buf = section; }
12670     if (n < buf_size) {
12671       *ip++ = target;
12672     }
12673     if (n < n_index_data) {
12674       index_data[n].index = target;
12675       index_data[n].section = section;
12676     }
12677     n++;
12678   }
12679 
12680   return n;
12681 }
12682 
12683 static int
grn_column_find_index_data_column_range(grn_ctx * ctx,grn_obj * obj,grn_operator op,grn_index_datum * index_data,unsigned int n_index_data,grn_obj ** index_buf,int buf_size,int * section_buf)12684 grn_column_find_index_data_column_range(grn_ctx *ctx, grn_obj *obj,
12685                                         grn_operator op,
12686                                         grn_index_datum *index_data,
12687                                         unsigned int n_index_data,
12688                                         grn_obj **index_buf, int buf_size,
12689                                         int *section_buf)
12690 {
12691   int n = 0;
12692   grn_obj **ip = index_buf;
12693   grn_hook_entry hook_entry;
12694   grn_hook *hooks;
12695 
12696   switch (obj->header.type) {
12697   case GRN_TABLE_HASH_KEY :
12698   case GRN_TABLE_PAT_KEY :
12699   case GRN_TABLE_DAT_KEY :
12700   case GRN_TABLE_NO_KEY :
12701     hook_entry = GRN_HOOK_INSERT;
12702     break;
12703   default :
12704     hook_entry = GRN_HOOK_SET;
12705     break;
12706   }
12707 
12708   for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
12709     grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12710     grn_obj *target = grn_ctx_at(ctx, data->target);
12711     int section;
12712     if (!target) { continue; }
12713     if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12714     section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12715     if (section_buf) { *section_buf = section; }
12716     {
12717       grn_obj *tokenizer, *lexicon = grn_ctx_at(ctx, target->header.domain);
12718       if (!lexicon) { continue; }
12719       if (lexicon->header.type != GRN_TABLE_PAT_KEY) { continue; }
12720       /* FIXME: GRN_TABLE_DAT_KEY should be supported */
12721       grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
12722       if (tokenizer) { continue; }
12723     }
12724     if (n < buf_size) {
12725       *ip++ = target;
12726     }
12727     if (n < n_index_data) {
12728       index_data[n].index = target;
12729       index_data[n].section = section;
12730     }
12731     n++;
12732   }
12733 
12734   return n;
12735 }
12736 
12737 static grn_bool
is_valid_match_index(grn_ctx * ctx,grn_obj * index_column)12738 is_valid_match_index(grn_ctx *ctx, grn_obj *index_column)
12739 {
12740   return GRN_TRUE;
12741 }
12742 
12743 static grn_bool
is_valid_range_index(grn_ctx * ctx,grn_obj * index_column)12744 is_valid_range_index(grn_ctx *ctx, grn_obj *index_column)
12745 {
12746   grn_obj *tokenizer;
12747   grn_obj *lexicon;
12748 
12749   lexicon = grn_ctx_at(ctx, index_column->header.domain);
12750   if (!lexicon) { return GRN_FALSE; }
12751   /* FIXME: GRN_TABLE_DAT_KEY should be supported */
12752   if (lexicon->header.type != GRN_TABLE_PAT_KEY) {
12753     grn_obj_unlink(ctx, lexicon);
12754     return GRN_FALSE;
12755   }
12756 
12757   grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
12758   grn_obj_unlink(ctx, lexicon);
12759   if (tokenizer) { return GRN_FALSE; }
12760 
12761   return GRN_TRUE;
12762 }
12763 
12764 static grn_bool
is_valid_index(grn_ctx * ctx,grn_obj * index_column,grn_operator op)12765 is_valid_index(grn_ctx *ctx, grn_obj *index_column, grn_operator op)
12766 {
12767   switch (op) {
12768   case GRN_OP_MATCH :
12769   case GRN_OP_NEAR :
12770   case GRN_OP_NEAR2 :
12771   case GRN_OP_SIMILAR :
12772     return is_valid_match_index(ctx, index_column);
12773     break;
12774   case GRN_OP_LESS :
12775   case GRN_OP_GREATER :
12776   case GRN_OP_LESS_EQUAL :
12777   case GRN_OP_GREATER_EQUAL :
12778   case GRN_OP_CALL :
12779     return is_valid_range_index(ctx, index_column);
12780     break;
12781   case GRN_OP_REGEXP :
12782     return is_valid_regexp_index(ctx, index_column);
12783     break;
12784   default :
12785     return GRN_FALSE;
12786     break;
12787   }
12788 }
12789 
12790 static int
find_section(grn_ctx * ctx,grn_obj * index_column,grn_obj * indexed_column)12791 find_section(grn_ctx *ctx, grn_obj *index_column, grn_obj *indexed_column)
12792 {
12793   int section = 0;
12794   grn_id indexed_column_id;
12795   grn_id *source_ids;
12796   int i, n_source_ids;
12797 
12798   indexed_column_id = DB_OBJ(indexed_column)->id;
12799 
12800   source_ids = DB_OBJ(index_column)->source;
12801   n_source_ids = DB_OBJ(index_column)->source_size / sizeof(grn_id);
12802   for (i = 0; i < n_source_ids; i++) {
12803     grn_id source_id = source_ids[i];
12804     if (source_id == indexed_column_id) {
12805       section = i + 1;
12806       break;
12807     }
12808   }
12809 
12810   return section;
12811 }
12812 
12813 static int
grn_column_find_index_data_accessor_index_column(grn_ctx * ctx,grn_accessor * a,grn_operator op,grn_index_datum * index_data,unsigned int n_index_data,grn_obj ** index_buf,int buf_size,int * section_buf)12814 grn_column_find_index_data_accessor_index_column(grn_ctx *ctx, grn_accessor *a,
12815                                                  grn_operator op,
12816                                                  grn_index_datum *index_data,
12817                                                  unsigned int n_index_data,
12818                                                  grn_obj **index_buf,
12819                                                  int buf_size,
12820                                                  int *section_buf)
12821 {
12822   grn_obj *index_column = a->obj;
12823   int section = 0;
12824 
12825   if (!is_valid_index(ctx, index_column, op)) {
12826     return 0;
12827   }
12828 
12829   if (a->next) {
12830     int specified_section;
12831     grn_bool is_invalid_section;
12832     if (a->next->next) {
12833       return 0;
12834     }
12835     specified_section = find_section(ctx, index_column, a->next->obj);
12836     is_invalid_section = (specified_section == 0);
12837     if (is_invalid_section) {
12838       return 0;
12839     }
12840     section = specified_section;
12841     if (section_buf) {
12842       *section_buf = section;
12843     }
12844   }
12845   if (buf_size > 0) {
12846     *index_buf = index_column;
12847   }
12848   if (n_index_data > 0) {
12849     index_data[0].index = index_column;
12850     index_data[0].section = section;
12851   }
12852 
12853   return 1;
12854 }
12855 
12856 static grn_bool
grn_column_find_index_data_accessor_is_key_search(grn_ctx * ctx,grn_accessor * accessor,grn_operator op)12857 grn_column_find_index_data_accessor_is_key_search(grn_ctx *ctx,
12858                                                   grn_accessor *accessor,
12859                                                   grn_operator op)
12860 {
12861   if (accessor->next) {
12862     return GRN_FALSE;
12863   }
12864 
12865   if (accessor->action != GRN_ACCESSOR_GET_KEY) {
12866     return GRN_FALSE;
12867   }
12868 
12869   if (!grn_obj_is_table(ctx, accessor->obj)) {
12870     return GRN_FALSE;
12871   }
12872 
12873   switch (op) {
12874   case GRN_OP_LESS :
12875   case GRN_OP_GREATER :
12876   case GRN_OP_LESS_EQUAL :
12877   case GRN_OP_GREATER_EQUAL :
12878     switch (accessor->obj->header.type) {
12879     case GRN_TABLE_PAT_KEY :
12880     case GRN_TABLE_DAT_KEY :
12881       return GRN_TRUE;
12882     default :
12883       return GRN_FALSE;
12884     }
12885   case GRN_OP_EQUAL :
12886     switch (accessor->obj->header.type) {
12887     case GRN_TABLE_HASH_KEY :
12888     case GRN_TABLE_PAT_KEY :
12889     case GRN_TABLE_DAT_KEY :
12890       return GRN_TRUE;
12891     default :
12892       return GRN_FALSE;
12893     }
12894   default :
12895     return GRN_FALSE;
12896   }
12897 }
12898 
12899 static int
grn_column_find_index_data_accessor_match(grn_ctx * ctx,grn_obj * obj,grn_operator op,grn_index_datum * index_data,unsigned n_index_data,grn_obj ** index_buf,int buf_size,int * section_buf)12900 grn_column_find_index_data_accessor_match(grn_ctx *ctx, grn_obj *obj,
12901                                           grn_operator op,
12902                                           grn_index_datum *index_data,
12903                                           unsigned n_index_data,
12904                                           grn_obj **index_buf, int buf_size,
12905                                           int *section_buf)
12906 {
12907   int n = 0;
12908   grn_obj **ip = index_buf;
12909   grn_accessor *a = (grn_accessor *)obj;
12910 
12911   while (a) {
12912     grn_hook *hooks;
12913     grn_bool found = GRN_FALSE;
12914     grn_hook_entry entry = (grn_hook_entry)-1;
12915 
12916     if (a->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
12917         GRN_OBJ_INDEX_COLUMNP(a->obj)) {
12918       return grn_column_find_index_data_accessor_index_column(ctx, a, op,
12919                                                               index_data,
12920                                                               n_index_data,
12921                                                               index_buf,
12922                                                               buf_size,
12923                                                               section_buf);
12924     }
12925 
12926     switch (a->action) {
12927     case GRN_ACCESSOR_GET_KEY :
12928       entry = GRN_HOOK_INSERT;
12929       break;
12930     case GRN_ACCESSOR_GET_COLUMN_VALUE :
12931       entry = GRN_HOOK_SET;
12932       break;
12933     default :
12934       break;
12935     }
12936 
12937     if (entry == (grn_hook_entry)-1) {
12938       break;
12939     }
12940 
12941     for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) {
12942       grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12943       grn_obj *target = grn_ctx_at(ctx, data->target);
12944 
12945       if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12946 
12947       found = GRN_TRUE;
12948       if (!a->next) {
12949         int section;
12950 
12951         if (!is_valid_index(ctx, target, op)) {
12952           continue;
12953         }
12954 
12955         section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12956         if (section_buf) {
12957           *section_buf = section;
12958         }
12959         if (n < buf_size) {
12960           *ip++ = target;
12961         }
12962         if (n < n_index_data) {
12963           index_data[n].index = target;
12964           index_data[n].section = section;
12965         }
12966         n++;
12967       }
12968     }
12969 
12970     if (!found &&
12971         grn_column_find_index_data_accessor_is_key_search(ctx, a, op)) {
12972       grn_obj *index;
12973       int section = 0;
12974 
12975       if ((grn_obj *)a == obj) {
12976         index = a->obj;
12977       } else {
12978         index = (grn_obj *)a;
12979       }
12980 
12981       found = GRN_TRUE;
12982       if (section_buf) {
12983         *section_buf = section;
12984       }
12985       if (n < buf_size) {
12986         *ip++ = index;
12987       }
12988       if (n < n_index_data) {
12989         index_data[n].index = index;
12990         index_data[n].section = section;
12991       }
12992       n++;
12993     }
12994 
12995     if (!found &&
12996         a->next &&
12997         grn_obj_is_table(ctx, a->obj) &&
12998         a->obj->header.domain == a->next->obj->header.domain) {
12999       grn_obj *index = (grn_obj *)a;
13000       int section = 0;
13001 
13002       found = GRN_TRUE;
13003       if (section_buf) {
13004         *section_buf = section;
13005       }
13006       if (n < buf_size) {
13007         *ip++ = index;
13008       }
13009       if (n < n_index_data) {
13010         index_data[n].index = index;
13011         index_data[n].section = section;
13012       }
13013       n++;
13014     }
13015 
13016     if (!found) {
13017       break;
13018     }
13019     a = a->next;
13020   }
13021 
13022   return n;
13023 }
13024 
13025 static int
grn_column_find_index_data_accessor(grn_ctx * ctx,grn_obj * obj,grn_operator op,grn_index_datum * index_data,unsigned n_index_data,grn_obj ** index_buf,int buf_size,int * section_buf)13026 grn_column_find_index_data_accessor(grn_ctx *ctx, grn_obj *obj,
13027                                     grn_operator op,
13028                                     grn_index_datum *index_data,
13029                                     unsigned n_index_data,
13030                                     grn_obj **index_buf, int buf_size,
13031                                     int *section_buf)
13032 {
13033   int n = 0;
13034 
13035   if (section_buf) {
13036     *section_buf = 0;
13037   }
13038   switch (op) {
13039   case GRN_OP_EQUAL :
13040   case GRN_OP_NOT_EQUAL :
13041   case GRN_OP_TERM_EXTRACT :
13042     if (buf_size > 0) {
13043       index_buf[n] = obj;
13044     }
13045     if (n_index_data > 0) {
13046       index_data[n].index   = obj;
13047       index_data[n].section = 0;
13048     }
13049     n++;
13050     break;
13051   case GRN_OP_PREFIX :
13052     {
13053       grn_accessor *a = (grn_accessor *)obj;
13054       if (a->action == GRN_ACCESSOR_GET_KEY) {
13055         if (a->obj->header.type == GRN_TABLE_PAT_KEY) {
13056           if (buf_size > 0) {
13057             index_buf[n] = obj;
13058           }
13059           if (n_index_data > 0) {
13060             index_data[n].index   = obj;
13061             index_data[n].section = 0;
13062           }
13063           n++;
13064         }
13065         /* FIXME: GRN_TABLE_DAT_KEY should be supported */
13066       }
13067     }
13068     break;
13069   case GRN_OP_SUFFIX :
13070     {
13071       grn_accessor *a = (grn_accessor *)obj;
13072       if (a->action == GRN_ACCESSOR_GET_KEY) {
13073         if (a->obj->header.type == GRN_TABLE_PAT_KEY &&
13074             a->obj->header.flags & GRN_OBJ_KEY_WITH_SIS) {
13075           if (buf_size > 0) {
13076             index_buf[n]         = obj;
13077           }
13078           if (n_index_data > 0) {
13079             index_data[n].index   = obj;
13080             index_data[n].section = 0;
13081           }
13082           n++;
13083         }
13084       }
13085     }
13086     break;
13087   case GRN_OP_MATCH :
13088   case GRN_OP_NEAR :
13089   case GRN_OP_NEAR2 :
13090   case GRN_OP_SIMILAR :
13091   case GRN_OP_LESS :
13092   case GRN_OP_GREATER :
13093   case GRN_OP_LESS_EQUAL :
13094   case GRN_OP_GREATER_EQUAL :
13095   case GRN_OP_CALL :
13096   case GRN_OP_REGEXP :
13097   case GRN_OP_FUZZY :
13098     n = grn_column_find_index_data_accessor_match(ctx, obj, op,
13099                                                   index_data, n_index_data,
13100                                                   index_buf, buf_size,
13101                                                   section_buf);
13102     break;
13103   default :
13104     break;
13105   }
13106 
13107   return n;
13108 }
13109 
13110 int
grn_column_index(grn_ctx * ctx,grn_obj * obj,grn_operator op,grn_obj ** index_buf,int buf_size,int * section_buf)13111 grn_column_index(grn_ctx *ctx, grn_obj *obj, grn_operator op,
13112                  grn_obj **index_buf, int buf_size, int *section_buf)
13113 {
13114   int n = 0;
13115   GRN_API_ENTER;
13116   if (GRN_DB_OBJP(obj)) {
13117     switch (op) {
13118     case GRN_OP_EQUAL :
13119     case GRN_OP_NOT_EQUAL :
13120       n = grn_column_find_index_data_column_equal(ctx, obj, op,
13121                                                   NULL, 0,
13122                                                   index_buf, buf_size,
13123                                                   section_buf);
13124       break;
13125     case GRN_OP_PREFIX :
13126     case GRN_OP_SUFFIX :
13127     case GRN_OP_MATCH :
13128     case GRN_OP_NEAR :
13129     case GRN_OP_NEAR2 :
13130     case GRN_OP_SIMILAR :
13131     case GRN_OP_REGEXP :
13132     case GRN_OP_FUZZY :
13133       n = grn_column_find_index_data_column_match(ctx, obj, op,
13134                                                   NULL, 0,
13135                                                   index_buf, buf_size,
13136                                                   section_buf);
13137       break;
13138     case GRN_OP_LESS :
13139     case GRN_OP_GREATER :
13140     case GRN_OP_LESS_EQUAL :
13141     case GRN_OP_GREATER_EQUAL :
13142     case GRN_OP_CALL :
13143       n = grn_column_find_index_data_column_range(ctx, obj, op,
13144                                                   NULL, 0,
13145                                                   index_buf, buf_size,
13146                                                   section_buf);
13147       break;
13148     default :
13149       break;
13150     }
13151   } else if (GRN_ACCESSORP(obj)) {
13152     n = grn_column_find_index_data_accessor(ctx, obj, op,
13153                                             NULL, 0,
13154                                             index_buf, buf_size,
13155                                             section_buf);
13156   }
13157   GRN_API_RETURN(n);
13158 }
13159 
13160 unsigned int
grn_column_find_index_data(grn_ctx * ctx,grn_obj * obj,grn_operator op,grn_index_datum * index_data,unsigned int n_index_data)13161 grn_column_find_index_data(grn_ctx *ctx, grn_obj *obj, grn_operator op,
13162                            grn_index_datum *index_data,
13163                            unsigned int n_index_data)
13164 {
13165   unsigned int n = 0;
13166   GRN_API_ENTER;
13167   if (GRN_DB_OBJP(obj)) {
13168     switch (op) {
13169     case GRN_OP_EQUAL :
13170     case GRN_OP_NOT_EQUAL :
13171       n = grn_column_find_index_data_column_equal(ctx, obj, op,
13172                                                   index_data, n_index_data,
13173                                                   NULL, 0, NULL);
13174       break;
13175     case GRN_OP_PREFIX :
13176     case GRN_OP_SUFFIX :
13177     case GRN_OP_MATCH :
13178     case GRN_OP_NEAR :
13179     case GRN_OP_NEAR2 :
13180     case GRN_OP_SIMILAR :
13181     case GRN_OP_REGEXP :
13182     case GRN_OP_FUZZY :
13183       n = grn_column_find_index_data_column_match(ctx, obj, op,
13184                                                   index_data, n_index_data,
13185                                                   NULL, 0, NULL);
13186       break;
13187     case GRN_OP_LESS :
13188     case GRN_OP_GREATER :
13189     case GRN_OP_LESS_EQUAL :
13190     case GRN_OP_GREATER_EQUAL :
13191     case GRN_OP_CALL :
13192       n = grn_column_find_index_data_column_range(ctx, obj, op,
13193                                                   index_data, n_index_data,
13194                                                   NULL, 0, NULL);
13195       break;
13196     default :
13197       break;
13198     }
13199   } else if (GRN_ACCESSORP(obj)) {
13200     n = grn_column_find_index_data_accessor(ctx, obj, op,
13201                                             index_data, n_index_data,
13202                                             NULL, 0, NULL);
13203   }
13204   GRN_API_RETURN(n);
13205 }
13206 
13207 static uint32_t
grn_column_get_all_index_data_column(grn_ctx * ctx,grn_obj * obj,grn_index_datum * index_data,uint32_t n_index_data)13208 grn_column_get_all_index_data_column(grn_ctx *ctx,
13209                                      grn_obj *obj,
13210                                      grn_index_datum *index_data,
13211                                      uint32_t n_index_data)
13212 {
13213   uint32_t n = 0;
13214   grn_hook_entry hook_entry;
13215   grn_hook *hooks;
13216 
13217   switch (obj->header.type) {
13218   case GRN_TABLE_HASH_KEY :
13219   case GRN_TABLE_PAT_KEY :
13220   case GRN_TABLE_DAT_KEY :
13221   case GRN_TABLE_NO_KEY :
13222     hook_entry = GRN_HOOK_INSERT;
13223     break;
13224   default :
13225     hook_entry = GRN_HOOK_SET;
13226     break;
13227   }
13228 
13229   for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
13230     grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
13231     grn_obj *target = grn_ctx_at(ctx, data->target);
13232     int section = 0;
13233     if (!target) {
13234       char name[GRN_TABLE_MAX_KEY_SIZE];
13235       int length;
13236       char hook_name[GRN_TABLE_MAX_KEY_SIZE];
13237       int hook_name_length;
13238 
13239       length = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
13240       hook_name_length = grn_table_get_key(ctx,
13241                                            ctx->impl->db,
13242                                            data->target,
13243                                            hook_name,
13244                                            GRN_TABLE_MAX_KEY_SIZE);
13245       ERR(GRN_OBJECT_CORRUPT,
13246           "[column][indexes][all] "
13247           "hook has a dangling reference: <%.*s> -> <%.*s>",
13248           length, name,
13249           hook_name_length, hook_name);
13250       continue;
13251     }
13252     if (target->header.type != GRN_COLUMN_INDEX) {
13253       continue;
13254     }
13255     if (MULTI_COLUMN_INDEXP(target)) {
13256       section = data->section;
13257     }
13258     if (n < n_index_data) {
13259       index_data[n].index = target;
13260       index_data[n].section = section;
13261     }
13262     n++;
13263   }
13264 
13265   return n;
13266 }
13267 
13268 static uint32_t
grn_column_get_all_index_data_accessor_index_column(grn_ctx * ctx,grn_accessor * a,grn_index_datum * index_data,uint32_t n_index_data)13269 grn_column_get_all_index_data_accessor_index_column(grn_ctx *ctx,
13270                                                     grn_accessor *a,
13271                                                     grn_index_datum *index_data,
13272                                                     uint32_t n_index_data)
13273 {
13274   grn_obj *index_column = a->obj;
13275   int section = 0;
13276 
13277   if (a->next) {
13278     int specified_section;
13279     grn_bool is_invalid_section;
13280     if (a->next->next) {
13281       return 0;
13282     }
13283     specified_section = find_section(ctx, index_column, a->next->obj);
13284     is_invalid_section = (specified_section == 0);
13285     if (is_invalid_section) {
13286       return 0;
13287     }
13288     section = specified_section;
13289   }
13290   if (n_index_data > 0) {
13291     index_data[0].index = index_column;
13292     index_data[0].section = section;
13293   }
13294 
13295   return 1;
13296 }
13297 
13298 static uint32_t
grn_column_get_all_index_data_accessor(grn_ctx * ctx,grn_obj * obj,grn_index_datum * index_data,uint32_t n_index_data)13299 grn_column_get_all_index_data_accessor(grn_ctx *ctx,
13300                                        grn_obj *obj,
13301                                        grn_index_datum *index_data,
13302                                        uint32_t n_index_data)
13303 {
13304   uint32_t n = 0;
13305   grn_accessor *a = (grn_accessor *)obj;
13306 
13307   while (a) {
13308     grn_hook *hooks;
13309     grn_bool found = GRN_FALSE;
13310     grn_hook_entry entry = (grn_hook_entry)-1;
13311 
13312     if (a->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
13313         GRN_OBJ_INDEX_COLUMNP(a->obj)) {
13314       return grn_column_get_all_index_data_accessor_index_column(ctx,
13315                                                                  a,
13316                                                                  index_data,
13317                                                                  n_index_data);
13318     }
13319 
13320     switch (a->action) {
13321     case GRN_ACCESSOR_GET_KEY :
13322       entry = GRN_HOOK_INSERT;
13323       break;
13324     case GRN_ACCESSOR_GET_COLUMN_VALUE :
13325       entry = GRN_HOOK_SET;
13326       break;
13327     default :
13328       break;
13329     }
13330 
13331     if (entry == (grn_hook_entry)-1) {
13332       break;
13333     }
13334 
13335     for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) {
13336       grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
13337       grn_obj *target = grn_ctx_at(ctx, data->target);
13338 
13339       if (target->header.type != GRN_COLUMN_INDEX) {
13340         continue;
13341       }
13342 
13343       found = GRN_TRUE;
13344       if (!a->next) {
13345         int section = 0;
13346 
13347         if (MULTI_COLUMN_INDEXP(target)) {
13348           section = data->section;
13349         }
13350         if (n < n_index_data) {
13351           index_data[n].index = target;
13352           index_data[n].section = section;
13353         }
13354         n++;
13355       }
13356     }
13357 
13358     if (!found) {
13359       break;
13360     }
13361     a = a->next;
13362   }
13363 
13364   return n;
13365 }
13366 
13367 uint32_t
grn_column_get_all_index_data(grn_ctx * ctx,grn_obj * obj,grn_index_datum * index_data,uint32_t n_index_data)13368 grn_column_get_all_index_data(grn_ctx *ctx,
13369                               grn_obj *obj,
13370                               grn_index_datum *index_data,
13371                               uint32_t n_index_data)
13372 {
13373   uint32_t n = 0;
13374   GRN_API_ENTER;
13375   if (GRN_DB_OBJP(obj)) {
13376     n = grn_column_get_all_index_data_column(ctx, obj,
13377                                              index_data, n_index_data);
13378   } else if (GRN_ACCESSORP(obj)) {
13379     n = grn_column_get_all_index_data_accessor(ctx, obj,
13380                                                index_data, n_index_data);
13381   }
13382   GRN_API_RETURN(n);
13383 }
13384 
13385 grn_rc
grn_obj_columns(grn_ctx * ctx,grn_obj * table,const char * str,unsigned int str_size,grn_obj * res)13386 grn_obj_columns(grn_ctx *ctx, grn_obj *table,
13387                 const char *str, unsigned int str_size, grn_obj *res)
13388 {
13389   grn_obj *col;
13390   const char *p = (char *)str, *q, *r, *pe = p + str_size, *tokbuf[256];
13391   while (p < pe) {
13392     int i, n = grn_tokenize(p, pe - p, tokbuf, 256, &q);
13393     for (i = 0; i < n; i++) {
13394       r = tokbuf[i];
13395       while (p < r && (' ' == *p || ',' == *p)) { p++; }
13396       if (p < r) {
13397         if (r[-1] == '*') {
13398           grn_hash *cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
13399                                            GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
13400           if (cols) {
13401             grn_id *key;
13402             grn_table_columns(ctx, table, p, r - p - 1, (grn_obj *)cols);
13403             GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
13404               if ((col = grn_ctx_at(ctx, *key))) { GRN_PTR_PUT(ctx, res, col); }
13405             });
13406             grn_hash_close(ctx, cols);
13407           }
13408           {
13409             grn_obj *type = grn_ctx_at(ctx, table->header.domain);
13410             if (GRN_OBJ_TABLEP(type)) {
13411               grn_obj *ai = grn_obj_column(ctx, table,
13412                                            GRN_COLUMN_NAME_ID,
13413                                            GRN_COLUMN_NAME_ID_LEN);
13414               if (ai) {
13415                 if (ai->header.type == GRN_ACCESSOR) {
13416                   grn_id *key;
13417                   grn_accessor *id_accessor;
13418                   for (id_accessor = ((grn_accessor *)ai)->next;
13419                        id_accessor;
13420                        id_accessor = id_accessor->next) {
13421                     grn_obj *target_table = id_accessor->obj;
13422 
13423                     cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
13424                                            GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
13425                     if (!cols) {
13426                       continue;
13427                     }
13428                     grn_table_columns(ctx, target_table,
13429                                       p, r - p - 1, (grn_obj *)cols);
13430                     GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
13431                       if ((col = grn_ctx_at(ctx, *key))) {
13432                         grn_accessor *a;
13433                         grn_accessor *ac;
13434                         ac = accessor_new(ctx);
13435                         GRN_PTR_PUT(ctx, res, (grn_obj *)ac);
13436                         for (a = (grn_accessor *)ai; a; a = a->next) {
13437                           if (a->action != GRN_ACCESSOR_GET_ID) {
13438                             ac->action = a->action;
13439                             ac->obj = a->obj;
13440                             ac->next = accessor_new(ctx);
13441                             if (!(ac = ac->next)) { break; }
13442                           } else {
13443                             ac->action = GRN_ACCESSOR_GET_COLUMN_VALUE;
13444                             ac->obj = col;
13445                             ac->next = NULL;
13446                             break;
13447                           }
13448                         }
13449                       }
13450                     });
13451                     grn_hash_close(ctx, cols);
13452                   }
13453                 }
13454                 grn_obj_unlink(ctx, ai);
13455               }
13456             }
13457           }
13458         } else if ((col = grn_obj_column(ctx, table, p, r - p))) {
13459           GRN_PTR_PUT(ctx, res, col);
13460         }
13461       }
13462       p = r;
13463     }
13464     p = q;
13465   }
13466   return ctx->rc;
13467 }
13468 
13469 static grn_table_sort_key *
grn_table_sort_key_from_str_geo(grn_ctx * ctx,const char * str,unsigned int str_size,grn_obj * table,unsigned int * nkeys)13470 grn_table_sort_key_from_str_geo(grn_ctx *ctx, const char *str, unsigned int str_size,
13471                                 grn_obj *table, unsigned int *nkeys)
13472 {
13473   const char **tokbuf;
13474   const char *p = str, *pe = str + str_size;
13475   grn_table_sort_key *keys = NULL, *k = NULL;
13476   while ((*p++ != '(')) { if (p == pe) { return NULL; } }
13477   str = p;
13478   while ((*p != ')')) { if (++p == pe) { return NULL; } }
13479   str_size = p - str;
13480   p = str;
13481   if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
13482     grn_id domain = GRN_ID_NIL;
13483     int i, n = grn_tokenize(str, str_size, tokbuf, str_size, NULL);
13484     if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
13485       k = keys;
13486       for (i = 0; i < n; i++) {
13487         const char *r = tokbuf[i];
13488         while (p < r && (' ' == *p || ',' == *p)) { p++; }
13489         if (p < r) {
13490           k->flags = GRN_TABLE_SORT_ASC;
13491           k->offset = 0;
13492           if (*p == '+') {
13493             p++;
13494           } else if (*p == '-') {
13495             k->flags = GRN_TABLE_SORT_DESC;
13496             p++;
13497           }
13498           if (k == keys) {
13499             if (!(k->key = grn_obj_column(ctx, table, p, r - p))) {
13500               WARN(GRN_INVALID_ARGUMENT, "invalid sort key: <%.*s>(<%.*s>)",
13501                    (int)(tokbuf[i] - p), p, str_size, str);
13502               break;
13503             }
13504             domain = grn_obj_get_range(ctx, k->key);
13505           } else {
13506             grn_obj buf;
13507             GRN_TEXT_INIT(&buf, GRN_OBJ_DO_SHALLOW_COPY);
13508             GRN_TEXT_SET(ctx, &buf, p + 1, r - p - 2); /* should be quoted */
13509             k->key = grn_obj_open(ctx, GRN_BULK, 0, domain);
13510             grn_obj_cast(ctx, &buf, k->key, GRN_FALSE);
13511             GRN_OBJ_FIN(ctx, &buf);
13512           }
13513           k->flags |= GRN_TABLE_SORT_GEO;
13514           k++;
13515         }
13516         p = r;
13517       }
13518     }
13519     GRN_FREE(tokbuf);
13520   }
13521   if (!ctx->rc && k - keys > 0) {
13522     *nkeys = k - keys;
13523   } else {
13524     grn_table_sort_key_close(ctx, keys, k - keys);
13525     *nkeys = 0;
13526     keys = NULL;
13527   }
13528   return keys;
13529 }
13530 
13531 grn_table_sort_key *
grn_table_sort_key_from_str(grn_ctx * ctx,const char * str,unsigned int str_size,grn_obj * table,unsigned int * nkeys)13532 grn_table_sort_key_from_str(grn_ctx *ctx, const char *str, unsigned int str_size,
13533                             grn_obj *table, unsigned int *nkeys)
13534 {
13535   const char *p = str;
13536   const char **tokbuf;
13537   grn_table_sort_key *keys = NULL, *k = NULL;
13538 
13539   if (str_size == 0) {
13540     return NULL;
13541   }
13542 
13543   if ((keys = grn_table_sort_key_from_str_geo(ctx, str, str_size, table, nkeys))) {
13544     return keys;
13545   }
13546   if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
13547     int i, n = grn_tokenize(str, str_size, tokbuf, str_size, NULL);
13548     if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
13549       k = keys;
13550       for (i = 0; i < n; i++) {
13551         const char *r = tokbuf[i];
13552         while (p < r && (' ' == *p || ',' == *p)) { p++; }
13553         if (p < r) {
13554           k->flags = GRN_TABLE_SORT_ASC;
13555           k->offset = 0;
13556           if (*p == '+') {
13557             p++;
13558           } else if (*p == '-') {
13559             k->flags = GRN_TABLE_SORT_DESC;
13560             p++;
13561           }
13562           if ((k->key = grn_obj_column(ctx, table, p, r - p))) {
13563             k++;
13564           } else {
13565             if (r - p == GRN_COLUMN_NAME_SCORE_LEN &&
13566                 memcmp(p, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN) == 0) {
13567               char table_name[GRN_TABLE_MAX_KEY_SIZE];
13568               int table_name_size;
13569               table_name_size = grn_obj_name(ctx, table,
13570                                              table_name,
13571                                              GRN_TABLE_MAX_KEY_SIZE);
13572               if (table_name_size == 0) {
13573                 grn_strcpy(table_name, GRN_TABLE_MAX_KEY_SIZE, "(anonymous)");
13574                 table_name_size = strlen(table_name);
13575               }
13576               GRN_LOG(ctx, GRN_WARN,
13577                       "ignore invalid sort key: <%.*s>: "
13578                       "table:<%*.s> keys:<%.*s>",
13579                       (int)(r - p), p,
13580                       table_name_size, table_name,
13581                       str_size, str);
13582             } else {
13583               char table_name[GRN_TABLE_MAX_KEY_SIZE];
13584               int table_name_size;
13585               table_name_size = grn_obj_name(ctx, table,
13586                                              table_name,
13587                                              GRN_TABLE_MAX_KEY_SIZE);
13588               if (table_name_size == 0) {
13589                 grn_strcpy(table_name, GRN_TABLE_MAX_KEY_SIZE, "(anonymous)");
13590                 table_name_size = strlen(table_name);
13591               }
13592               WARN(GRN_INVALID_ARGUMENT,
13593                    "invalid sort key: <%.*s>: "
13594                    "table:<%.*s> keys:<%.*s>",
13595                    (int)(r - p), p,
13596                    table_name_size, table_name,
13597                    str_size, str);
13598               break;
13599             }
13600           }
13601         }
13602         p = r;
13603       }
13604     }
13605     GRN_FREE(tokbuf);
13606   }
13607   if (!ctx->rc && k - keys > 0) {
13608     *nkeys = k - keys;
13609   } else {
13610     grn_table_sort_key_close(ctx, keys, k - keys);
13611     *nkeys = 0;
13612     keys = NULL;
13613   }
13614   return keys;
13615 }
13616 
13617 grn_rc
grn_table_sort_key_close(grn_ctx * ctx,grn_table_sort_key * keys,unsigned int nkeys)13618 grn_table_sort_key_close(grn_ctx *ctx, grn_table_sort_key *keys, unsigned int nkeys)
13619 {
13620   int i;
13621   if (keys) {
13622     for (i = 0; i < nkeys; i++) {
13623       grn_obj *key = keys[i].key;
13624       if (!grn_obj_is_column(ctx, key)) {
13625         grn_obj_unlink(ctx, key);
13626       }
13627     }
13628     GRN_FREE(keys);
13629   }
13630   return ctx->rc;
13631 }
13632 
13633 grn_bool
grn_table_is_grouped(grn_ctx * ctx,grn_obj * table)13634 grn_table_is_grouped(grn_ctx *ctx, grn_obj *table)
13635 {
13636   if (GRN_OBJ_TABLEP(table) && GRN_TABLE_IS_GROUPED(table)) {
13637     return GRN_TRUE;
13638   }
13639   return GRN_FALSE;
13640 }
13641 
13642 unsigned int
grn_table_max_n_subrecs(grn_ctx * ctx,grn_obj * table)13643 grn_table_max_n_subrecs(grn_ctx *ctx, grn_obj *table)
13644 {
13645   if (GRN_OBJ_TABLEP(table)) {
13646     return DB_OBJ(table)->max_n_subrecs;
13647   }
13648   return 0;
13649 }
13650 
13651 grn_obj *
grn_table_tokenize(grn_ctx * ctx,grn_obj * table,const char * str,unsigned int str_len,grn_obj * buf,grn_bool addp)13652 grn_table_tokenize(grn_ctx *ctx, grn_obj *table,
13653                    const char *str, unsigned int str_len,
13654                    grn_obj *buf, grn_bool addp)
13655 {
13656   grn_token_cursor *token_cursor = NULL;
13657   grn_tokenize_mode mode = addp ? GRN_TOKENIZE_ADD : GRN_TOKENIZE_GET;
13658   GRN_API_ENTER;
13659   if (!(token_cursor = grn_token_cursor_open(ctx, table, str, str_len, mode, 0))) {
13660     goto exit;
13661   }
13662   if (buf) {
13663     GRN_BULK_REWIND(buf);
13664   } else {
13665     if (!(buf = grn_obj_open(ctx, GRN_UVECTOR, 0, DB_OBJ(table)->id))) {
13666       goto exit;
13667     }
13668   }
13669   while (token_cursor->status != GRN_TOKEN_CURSOR_DONE && token_cursor->status != GRN_TOKEN_CURSOR_DONE_SKIP) {
13670     grn_id tid;
13671     if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
13672       GRN_RECORD_PUT(ctx, buf, tid);
13673     }
13674   }
13675 exit :
13676   if (token_cursor) {
13677     grn_token_cursor_close(ctx, token_cursor);
13678   }
13679   GRN_API_RETURN(buf);
13680 }
13681 
13682 static void
grn_db_recover_database_remove_orphan_inspect(grn_ctx * ctx,grn_obj * db)13683 grn_db_recover_database_remove_orphan_inspect(grn_ctx *ctx, grn_obj *db)
13684 {
13685   GRN_TABLE_EACH_BEGIN_FLAGS(ctx, db, cursor, id, GRN_CURSOR_BY_ID) {
13686     void *key;
13687     int key_size;
13688 
13689     key_size = grn_table_cursor_get_key(ctx, cursor, &key);
13690 #define INSPECT     "inspect"
13691 #define INSPECT_LEN (sizeof(INSPECT) - 1)
13692     if (key_size == INSPECT_LEN && memcmp(key, INSPECT, INSPECT_LEN) == 0) {
13693       if (!grn_ctx_at(ctx, id)) {
13694         ERRCLR(ctx);
13695         grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
13696       }
13697       break;
13698     }
13699 #undef INSPECT
13700 #undef INSPECT_LEN
13701   } GRN_TABLE_EACH_END(ctx, cursor);
13702 }
13703 
13704 static void
grn_db_recover_database(grn_ctx * ctx,grn_obj * db)13705 grn_db_recover_database(grn_ctx *ctx, grn_obj *db)
13706 {
13707   if (grn_obj_is_locked(ctx, db)) {
13708     ERR(GRN_OBJECT_CORRUPT,
13709         "[db][recover] database may be broken. Please re-create the database");
13710     return;
13711   }
13712 
13713   grn_db_clear_dirty(ctx, db);
13714   grn_db_recover_database_remove_orphan_inspect(ctx, db);
13715 }
13716 
13717 static void
grn_db_recover_table(grn_ctx * ctx,grn_obj * table)13718 grn_db_recover_table(grn_ctx *ctx, grn_obj *table)
13719 {
13720   if (!grn_obj_is_locked(ctx, table)) {
13721     return;
13722   }
13723 
13724   {
13725     char name[GRN_TABLE_MAX_KEY_SIZE];
13726     unsigned int name_size;
13727     name_size = grn_obj_name(ctx, table, name, GRN_TABLE_MAX_KEY_SIZE);
13728     ERR(GRN_OBJECT_CORRUPT,
13729         "[db][recover] table may be broken: <%.*s>: "
13730         "please truncate the table (or clear lock of the table) "
13731         "and load data again",
13732         (int)name_size, name);
13733   }
13734 }
13735 
13736 static void
grn_db_recover_data_column(grn_ctx * ctx,grn_obj * data_column)13737 grn_db_recover_data_column(grn_ctx *ctx, grn_obj *data_column)
13738 {
13739   if (!grn_obj_is_locked(ctx, data_column)) {
13740     return;
13741   }
13742 
13743   {
13744     char name[GRN_TABLE_MAX_KEY_SIZE];
13745     unsigned int name_size;
13746     name_size = grn_obj_name(ctx, data_column, name, GRN_TABLE_MAX_KEY_SIZE);
13747     ERR(GRN_OBJECT_CORRUPT,
13748         "[db][recover] column may be broken: <%.*s>: "
13749         "please truncate the column (or clear lock of the column) "
13750         "and load data again",
13751         (int)name_size, name);
13752   }
13753 }
13754 
13755 static void
grn_db_recover_index_column(grn_ctx * ctx,grn_obj * index_column)13756 grn_db_recover_index_column(grn_ctx *ctx, grn_obj *index_column)
13757 {
13758   if (!grn_obj_is_locked(ctx, index_column)) {
13759     return;
13760   }
13761 
13762   grn_index_column_rebuild(ctx, index_column);
13763 }
13764 
13765 static grn_bool
grn_db_recover_is_builtin(grn_ctx * ctx,grn_id id,grn_table_cursor * cursor)13766 grn_db_recover_is_builtin(grn_ctx *ctx, grn_id id, grn_table_cursor *cursor)
13767 {
13768   void *key;
13769   const char *name;
13770   int name_size;
13771 
13772   if (id < GRN_N_RESERVED_TYPES) {
13773     return GRN_TRUE;
13774   }
13775 
13776   name_size = grn_table_cursor_get_key(ctx, cursor, &key);
13777   name = key;
13778 
13779 #define NAME_EQUAL(value)                       \
13780   (name_size == strlen(value) && memcmp(name, value, strlen(value)) == 0)
13781 
13782   if (NAME_EQUAL("inspect")) {
13783     /* Just for compatibility. It's needed for users who used
13784        Groonga master at between 2016-02-03 and 2016-02-26. */
13785     return GRN_TRUE;
13786   }
13787 
13788 #undef NAME_EQUAL
13789 
13790   return GRN_FALSE;
13791 }
13792 
13793 grn_rc
grn_db_recover(grn_ctx * ctx,grn_obj * db)13794 grn_db_recover(grn_ctx *ctx, grn_obj *db)
13795 {
13796   grn_table_cursor *cursor;
13797   grn_id id;
13798   grn_bool is_close_opened_object_mode;
13799 
13800   GRN_API_ENTER;
13801 
13802   is_close_opened_object_mode = (grn_thread_get_limit() == 1);
13803 
13804   grn_db_recover_database(ctx, db);
13805   if (ctx->rc != GRN_SUCCESS) {
13806     GRN_API_RETURN(ctx->rc);
13807   }
13808 
13809   cursor = grn_table_cursor_open(ctx, db,
13810                                  NULL, 0, NULL, 0,
13811                                  0, -1,
13812                                  GRN_CURSOR_BY_ID);
13813   if (!cursor) {
13814     GRN_API_RETURN(ctx->rc);
13815   }
13816 
13817   while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
13818     grn_obj *object;
13819 
13820     if (is_close_opened_object_mode) {
13821       grn_ctx_push_temporary_open_space(ctx);
13822     }
13823 
13824     if ((object = grn_ctx_at(ctx, id))) {
13825       switch (object->header.type) {
13826       case GRN_TABLE_NO_KEY :
13827       case GRN_TABLE_HASH_KEY :
13828       case GRN_TABLE_PAT_KEY :
13829       case GRN_TABLE_DAT_KEY :
13830         grn_db_recover_table(ctx, object);
13831         break;
13832       case GRN_COLUMN_FIX_SIZE :
13833       case GRN_COLUMN_VAR_SIZE :
13834         grn_db_recover_data_column(ctx, object);
13835         break;
13836       case GRN_COLUMN_INDEX :
13837         grn_db_recover_index_column(ctx, object);
13838         break;
13839       default:
13840         break;
13841       }
13842       grn_obj_unlink(ctx, object);
13843     } else {
13844       if (grn_db_recover_is_builtin(ctx, id, cursor)) {
13845         ERRCLR(ctx);
13846       }
13847     }
13848 
13849     if (is_close_opened_object_mode) {
13850       grn_ctx_pop_temporary_open_space(ctx);
13851     }
13852 
13853     if (ctx->rc != GRN_SUCCESS) {
13854       break;
13855     }
13856   }
13857   grn_table_cursor_close(ctx, cursor);
13858 
13859   GRN_API_RETURN(ctx->rc);
13860 }
13861 
13862 grn_rc
grn_db_unmap(grn_ctx * ctx,grn_obj * db)13863 grn_db_unmap(grn_ctx *ctx, grn_obj *db)
13864 {
13865   grn_id id;
13866   db_value *vp;
13867   grn_db *s = (grn_db *)db;
13868 
13869   GRN_API_ENTER;
13870 
13871   GRN_TINY_ARRAY_EACH(&s->values, 1, grn_db_curr_id(ctx, db), id, vp, {
13872     grn_obj *obj = vp->ptr;
13873 
13874     if (obj) {
13875       switch (obj->header.type) {
13876       case GRN_TABLE_HASH_KEY :
13877       case GRN_TABLE_PAT_KEY :
13878       case GRN_TABLE_DAT_KEY :
13879       case GRN_TABLE_NO_KEY :
13880       case GRN_COLUMN_FIX_SIZE :
13881       case GRN_COLUMN_VAR_SIZE :
13882       case GRN_COLUMN_INDEX :
13883         grn_obj_close(ctx, obj);
13884         break;
13885       }
13886     }
13887   });
13888 
13889   GRN_API_RETURN(ctx->rc);
13890 }
13891 
13892 static grn_rc
grn_ctx_get_all_objects(grn_ctx * ctx,grn_obj * objects_buffer,grn_bool (* predicate)(grn_ctx * ctx,grn_obj * object))13893 grn_ctx_get_all_objects(grn_ctx *ctx, grn_obj *objects_buffer,
13894                         grn_bool (*predicate)(grn_ctx *ctx, grn_obj *object))
13895 {
13896   grn_obj *db;
13897   grn_table_cursor *cursor;
13898   grn_id id;
13899 
13900   GRN_API_ENTER;
13901 
13902   db = ctx->impl->db;
13903   if (!db) {
13904     ERR(GRN_INVALID_ARGUMENT, "DB isn't associated");
13905     GRN_API_RETURN(ctx->rc);
13906   }
13907 
13908   cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0);
13909   if (!cursor) {
13910     GRN_API_RETURN(ctx->rc);
13911   }
13912 
13913   while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
13914     grn_obj *object;
13915 
13916     if ((object = grn_ctx_at(ctx, id))) {
13917       if (predicate(ctx, object)) {
13918         GRN_PTR_PUT(ctx, objects_buffer, object);
13919       } else {
13920         grn_obj_unlink(ctx, object);
13921       }
13922     } else {
13923       if (ctx->rc != GRN_SUCCESS) {
13924         ERRCLR(ctx);
13925       }
13926     }
13927   }
13928   grn_table_cursor_close(ctx, cursor);
13929 
13930   GRN_API_RETURN(ctx->rc);
13931 }
13932 
13933 grn_rc
grn_ctx_get_all_tables(grn_ctx * ctx,grn_obj * tables_buffer)13934 grn_ctx_get_all_tables(grn_ctx *ctx, grn_obj *tables_buffer)
13935 {
13936   return grn_ctx_get_all_objects(ctx, tables_buffer, grn_obj_is_table);
13937 }
13938 
13939 grn_rc
grn_ctx_get_all_types(grn_ctx * ctx,grn_obj * types_buffer)13940 grn_ctx_get_all_types(grn_ctx *ctx, grn_obj *types_buffer)
13941 {
13942   return grn_ctx_get_all_objects(ctx, types_buffer, grn_obj_is_type);
13943 }
13944 
13945 grn_rc
grn_ctx_get_all_tokenizers(grn_ctx * ctx,grn_obj * tokenizers_buffer)13946 grn_ctx_get_all_tokenizers(grn_ctx *ctx, grn_obj *tokenizers_buffer)
13947 {
13948   return grn_ctx_get_all_objects(ctx, tokenizers_buffer,
13949                                  grn_obj_is_tokenizer_proc);
13950 }
13951 
13952 grn_rc
grn_ctx_get_all_normalizers(grn_ctx * ctx,grn_obj * normalizers_buffer)13953 grn_ctx_get_all_normalizers(grn_ctx *ctx, grn_obj *normalizers_buffer)
13954 {
13955   return grn_ctx_get_all_objects(ctx, normalizers_buffer,
13956                                  grn_obj_is_normalizer_proc);
13957 }
13958 
13959 grn_rc
grn_ctx_get_all_token_filters(grn_ctx * ctx,grn_obj * token_filters_buffer)13960 grn_ctx_get_all_token_filters(grn_ctx *ctx, grn_obj *token_filters_buffer)
13961 {
13962   return grn_ctx_get_all_objects(ctx, token_filters_buffer,
13963                                  grn_obj_is_token_filter_proc);
13964 }
13965 
13966 grn_rc
grn_ctx_push_temporary_open_space(grn_ctx * ctx)13967 grn_ctx_push_temporary_open_space(grn_ctx *ctx)
13968 {
13969   grn_obj *stack;
13970   grn_obj *space;
13971   grn_obj buffer;
13972 
13973   GRN_API_ENTER;
13974 
13975   stack = &(ctx->impl->temporary_open_spaces.stack);
13976   GRN_VOID_INIT(&buffer);
13977   grn_bulk_write(ctx, stack, (const char *)&buffer, sizeof(grn_obj));
13978   space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
13979   GRN_PTR_INIT(space, GRN_OBJ_VECTOR | GRN_OBJ_OWN, GRN_ID_NIL);
13980 
13981   ctx->impl->temporary_open_spaces.current = space;
13982 
13983   GRN_API_RETURN(ctx->rc);
13984 }
13985 
13986 grn_rc
grn_ctx_pop_temporary_open_space(grn_ctx * ctx)13987 grn_ctx_pop_temporary_open_space(grn_ctx *ctx)
13988 {
13989   grn_obj *stack;
13990   grn_obj *space;
13991 
13992   GRN_API_ENTER;
13993 
13994   stack = &(ctx->impl->temporary_open_spaces.stack);
13995   if (GRN_BULK_EMPTYP(stack)) {
13996     ERR(GRN_INVALID_ARGUMENT,
13997         "[ctx][temporary-open-spaces][pop] too much pop");
13998     GRN_API_RETURN(ctx->rc);
13999   }
14000 
14001   space = ctx->impl->temporary_open_spaces.current;
14002   GRN_OBJ_FIN(ctx, space);
14003   grn_bulk_truncate(ctx, stack, GRN_BULK_VSIZE(stack) - sizeof(grn_obj));
14004 
14005   if (GRN_BULK_EMPTYP(stack)) {
14006     space = NULL;
14007   } else {
14008     space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
14009   }
14010   ctx->impl->temporary_open_spaces.current = space;
14011 
14012   GRN_API_RETURN(ctx->rc);
14013 }
14014 
14015 grn_rc
grn_ctx_merge_temporary_open_space(grn_ctx * ctx)14016 grn_ctx_merge_temporary_open_space(grn_ctx *ctx)
14017 {
14018   grn_obj *stack;
14019   grn_obj *space;
14020   grn_obj *next_space;
14021 
14022   GRN_API_ENTER;
14023 
14024   stack = &(ctx->impl->temporary_open_spaces.stack);
14025   if (GRN_BULK_VSIZE(stack) < sizeof(grn_obj) * 2) {
14026     ERR(GRN_INVALID_ARGUMENT,
14027         "[ctx][temporary-open-spaces][merge] "
14028         "merge requires at least two spaces");
14029     GRN_API_RETURN(ctx->rc);
14030   }
14031 
14032   space = ctx->impl->temporary_open_spaces.current;
14033   next_space = ctx->impl->temporary_open_spaces.current - 1;
14034   {
14035     unsigned int i, n_elements;
14036     n_elements = GRN_BULK_VSIZE(space) / sizeof(grn_obj *);
14037     for (i = 0; i < n_elements; i++) {
14038       grn_obj *element = GRN_PTR_VALUE_AT(space, i);
14039       GRN_PTR_PUT(ctx, next_space, element);
14040     }
14041   }
14042   GRN_BULK_REWIND(space);
14043   GRN_OBJ_FIN(ctx, space);
14044   grn_bulk_truncate(ctx, stack, GRN_BULK_VSIZE(stack) - sizeof(grn_obj));
14045 
14046   if (GRN_BULK_EMPTYP(stack)) {
14047     space = NULL;
14048   } else {
14049     space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
14050   }
14051   ctx->impl->temporary_open_spaces.current = space;
14052 
14053   GRN_API_RETURN(ctx->rc);
14054 }
14055