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 ¤t_spec_raw_len);
8485 if (current_spec_raw) {
8486 grn_rc rc;
8487 grn_obj current_spec;
8488
8489 GRN_OBJ_INIT(¤t_spec, GRN_VECTOR, 0, GRN_DB_TEXT);
8490 rc = grn_vector_decode(ctx,
8491 ¤t_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, ¤t_spec);
8496 }
8497 GRN_OBJ_FIN(ctx, ¤t_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