1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2009-2017 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18#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
44typedef 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
76inline static grn_id
77grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
78 void **value, int *added);
79inline static void
80grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, double score,
81 grn_rset_posinfo *pi, int dir);
82inline static grn_id
83grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc);
84inline static int
85grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value);
86
87static void grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj);
88static void grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj);
89
90inline static void
91grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj,
92 grn_id *range_id, grn_obj_flags *range_flags);
93
94static char grn_db_key[GRN_ENV_BUFFER_SIZE];
95
96void
97grn_db_init_from_env(void)
98{
99 grn_getenv("GRN_DB_KEY",
100 grn_db_key,
101 GRN_ENV_BUFFER_SIZE);
102}
103
104inline static void
105gen_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
118void
119grn_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
124typedef struct {
125 grn_obj *ptr;
126 uint32_t lock;
127 uint32_t done;
128} db_value;
129
130static const char *GRN_DB_CONFIG_PATH_FORMAT = "%s.conf";
131
132static grn_bool
133grn_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
162static grn_bool
163grn_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
182static grn_rc
183grn_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
191grn_obj *
192grn_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
278exit:
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
303grn_obj *
304grn_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
399exit:
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
419static grn_id
420grn_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 */
436grn_rc
437grn_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 grn_ctx_loader_clear(ctx);
449 if (ctx->impl->parser) {
450 grn_expr_parser_close(ctx);
451 }
452 }
453
454 GRN_TINY_ARRAY_EACH(&s->values, 1, grn_db_curr_id(ctx, db), id, vp, {
455 if (vp->ptr) { grn_obj_close(ctx, vp->ptr); }
456 });
457
458 if (ctx_used_db) {
459 if (ctx->impl->values) {
460 grn_db_obj *o;
461 GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, {
462 grn_obj_close(ctx, *((grn_obj **)o));
463 });
464 grn_array_truncate(ctx, ctx->impl->values);
465 }
466 }
467
468/* grn_tiny_array_fin should be refined.. */
469#ifdef WIN32
470 {
471 grn_tiny_array *a = &s->values;
472 CRITICAL_SECTION_FIN(a->lock);
473 }
474#endif
475 grn_tiny_array_fin(&s->values);
476
477 switch (s->keys->header.type) {
478 case GRN_TABLE_PAT_KEY :
479 grn_pat_close(ctx, (grn_pat *)s->keys);
480 break;
481 case GRN_TABLE_DAT_KEY :
482 grn_dat_close(ctx, (grn_dat *)s->keys);
483 break;
484 }
485 CRITICAL_SECTION_FIN(s->lock);
486 if (s->specs) { grn_ja_close(ctx, s->specs); }
487 grn_hash_close(ctx, s->config);
488 GRN_FREE(s);
489
490 if (ctx_used_db) {
491 grn_cache *cache;
492 cache = grn_cache_current_get(ctx);
493 if (cache) {
494 grn_cache_expire(cache, -1);
495 }
496 ctx->impl->db = NULL;
497 }
498
499 GRN_API_RETURN(GRN_SUCCESS);
500}
501
502grn_obj *
503grn_ctx_get(grn_ctx *ctx, const char *name, int name_size)
504{
505 grn_obj *obj = NULL;
506 grn_obj *db;
507 if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
508 return NULL;
509 }
510 GRN_API_ENTER;
511 if (GRN_DB_P(db)) {
512 grn_db *s = (grn_db *)db;
513 grn_obj *alias_table = NULL;
514 grn_obj *alias_column = NULL;
515 grn_obj alias_name_buffer;
516
517 if (name_size < 0) {
518 name_size = strlen(name);
519 }
520 GRN_TEXT_INIT(&alias_name_buffer, 0);
521 while (GRN_TRUE) {
522 grn_id id;
523
524 id = grn_table_get(ctx, s->keys, name, name_size);
525 if (id) {
526 obj = grn_ctx_at(ctx, id);
527 break;
528 }
529
530 if (!alias_column) {
531 grn_id alias_column_id;
532 const char *alias_column_name;
533 uint32_t alias_column_name_size;
534
535 grn_config_get(ctx,
536 "alias.column", -1,
537 &alias_column_name, &alias_column_name_size);
538 if (!alias_column_name) {
539 break;
540 }
541 alias_column_id = grn_table_get(ctx,
542 s->keys,
543 alias_column_name,
544 alias_column_name_size);
545 if (!alias_column_id) {
546 break;
547 }
548 alias_column = grn_ctx_at(ctx, alias_column_id);
549 if (alias_column->header.type != GRN_COLUMN_VAR_SIZE) {
550 break;
551 }
552 if (alias_column->header.flags & GRN_OBJ_VECTOR) {
553 break;
554 }
555 if (DB_OBJ(alias_column)->range != GRN_DB_SHORT_TEXT) {
556 break;
557 }
558 alias_table = grn_ctx_at(ctx, alias_column->header.domain);
559 if (alias_table->header.type == GRN_TABLE_NO_KEY) {
560 break;
561 }
562 }
563
564 {
565 grn_id alias_id;
566 alias_id = grn_table_get(ctx, alias_table, name, name_size);
567 if (!alias_id) {
568 break;
569 }
570 GRN_BULK_REWIND(&alias_name_buffer);
571 grn_obj_get_value(ctx, alias_column, alias_id, &alias_name_buffer);
572 name = GRN_TEXT_VALUE(&alias_name_buffer);
573 name_size = GRN_TEXT_LEN(&alias_name_buffer);
574 }
575 }
576 GRN_OBJ_FIN(ctx, &alias_name_buffer);
577 }
578 GRN_API_RETURN(obj);
579}
580
581grn_obj *
582grn_ctx_db(grn_ctx *ctx)
583{
584 return (ctx && ctx->impl) ? ctx->impl->db : NULL;
585}
586
587grn_obj *
588grn_db_keys(grn_obj *s)
589{
590 return (grn_obj *)(((grn_db *)s)->keys);
591}
592
593uint32_t
594grn_obj_get_last_modified(grn_ctx *ctx, grn_obj *obj)
595{
596 if (!obj) {
597 return 0;
598 }
599
600 return grn_obj_get_io(ctx, obj)->header->last_modified;
601}
602
603grn_bool
604grn_obj_is_dirty(grn_ctx *ctx, grn_obj *obj)
605{
606 if (!obj) {
607 return GRN_FALSE;
608 }
609
610 switch (obj->header.type) {
611 case GRN_DB :
612 return grn_db_is_dirty(ctx, obj);
613 case GRN_TABLE_PAT_KEY :
614 return grn_pat_is_dirty(ctx, (grn_pat *)obj);
615 case GRN_TABLE_DAT_KEY :
616 return grn_dat_is_dirty(ctx, (grn_dat *)obj);
617 default :
618 return GRN_FALSE;
619 }
620}
621
622uint32_t
623grn_db_get_last_modified(grn_ctx *ctx, grn_obj *db)
624{
625 return grn_obj_get_last_modified(ctx, db);
626}
627
628grn_bool
629grn_db_is_dirty(grn_ctx *ctx, grn_obj *db)
630{
631 grn_obj *keys;
632
633 if (!db) {
634 return GRN_FALSE;
635 }
636
637 keys = ((grn_db *)db)->keys;
638 return grn_obj_is_dirty(ctx, keys);
639}
640
641static grn_rc
642grn_db_dirty(grn_ctx *ctx, grn_obj *db)
643{
644 grn_obj *keys;
645
646 if (!db) {
647 return GRN_SUCCESS;
648 }
649
650 keys = ((grn_db *)db)->keys;
651 switch (keys->header.type) {
652 case GRN_TABLE_PAT_KEY :
653 return grn_pat_dirty(ctx, (grn_pat *)keys);
654 case GRN_TABLE_DAT_KEY :
655 return grn_dat_dirty(ctx, (grn_dat *)keys);
656 default :
657 return GRN_SUCCESS;
658 }
659}
660
661static grn_rc
662grn_db_clean(grn_ctx *ctx, grn_obj *db)
663{
664 grn_obj *keys;
665
666 if (!db) {
667 return GRN_SUCCESS;
668 }
669
670 keys = ((grn_db *)db)->keys;
671 switch (keys->header.type) {
672 case GRN_TABLE_PAT_KEY :
673 return grn_pat_clean(ctx, (grn_pat *)keys);
674 case GRN_TABLE_DAT_KEY :
675 return grn_dat_clean(ctx, (grn_dat *)keys);
676 default :
677 return GRN_SUCCESS;
678 }
679}
680
681static grn_rc
682grn_db_clear_dirty(grn_ctx *ctx, grn_obj *db)
683{
684 grn_obj *keys;
685
686 if (!db) {
687 return GRN_SUCCESS;
688 }
689
690 keys = ((grn_db *)db)->keys;
691 switch (keys->header.type) {
692 case GRN_TABLE_PAT_KEY :
693 return grn_pat_clear_dirty(ctx, (grn_pat *)keys);
694 case GRN_TABLE_DAT_KEY :
695 return grn_dat_clear_dirty(ctx, (grn_dat *)keys);
696 default :
697 return GRN_SUCCESS;
698 }
699}
700
701void
702grn_db_touch(grn_ctx *ctx, grn_obj *s)
703{
704 grn_obj_touch(ctx, s, NULL);
705}
706
707grn_bool
708grn_obj_is_corrupt(grn_ctx *ctx, grn_obj *obj)
709{
710 grn_bool is_corrupt = GRN_FALSE;
711
712 GRN_API_ENTER;
713
714 if (!obj) {
715 ERR(GRN_INVALID_ARGUMENT, "[object][corrupt] object must not be NULL");
716 GRN_API_RETURN(GRN_FALSE);
717 }
718
719 switch (obj->header.type) {
720 case GRN_DB :
721 is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
722 if (!is_corrupt) {
723 is_corrupt = grn_io_is_corrupt(ctx, ((grn_db *)obj)->specs->io);
724 }
725 if (!is_corrupt) {
726 is_corrupt = grn_io_is_corrupt(ctx, ((grn_db *)obj)->config->io);
727 }
728 break;
729 case GRN_TABLE_HASH_KEY :
730 case GRN_TABLE_PAT_KEY :
731 is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
732 break;
733 case GRN_TABLE_DAT_KEY :
734 is_corrupt = grn_dat_is_corrupt(ctx, (grn_dat *)obj);
735 break;
736 case GRN_COLUMN_FIX_SIZE :
737 case GRN_COLUMN_VAR_SIZE :
738 is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
739 break;
740 case GRN_COLUMN_INDEX :
741 is_corrupt = grn_io_is_corrupt(ctx, ((grn_ii *)obj)->seg);
742 if (!is_corrupt) {
743 is_corrupt = grn_io_is_corrupt(ctx, ((grn_ii *)obj)->chunk);
744 }
745 break;
746 default :
747 break;
748 }
749
750 GRN_API_RETURN(is_corrupt);
751}
752
753#define IS_TEMP(obj) (DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)
754
755static inline void
756grn_obj_touch_db(grn_ctx *ctx, grn_obj *obj, grn_timeval *tv)
757{
758 grn_obj_get_io(ctx, obj)->header->last_modified = tv->tv_sec;
759 grn_db_dirty(ctx, obj);
760}
761
762void
763grn_obj_touch(grn_ctx *ctx, grn_obj *obj, grn_timeval *tv)
764{
765 grn_timeval tv_;
766 if (!tv) {
767 grn_timeval_now(ctx, &tv_);
768 tv = &tv_;
769 }
770 if (obj) {
771 switch (obj->header.type) {
772 case GRN_DB :
773 grn_obj_touch_db(ctx, obj, tv);
774 break;
775 case GRN_TABLE_HASH_KEY :
776 case GRN_TABLE_PAT_KEY :
777 case GRN_TABLE_DAT_KEY :
778 case GRN_TABLE_NO_KEY :
779 case GRN_COLUMN_VAR_SIZE :
780 case GRN_COLUMN_FIX_SIZE :
781 case GRN_COLUMN_INDEX :
782 if (!IS_TEMP(obj)) {
783 grn_obj_get_io(ctx, obj)->header->last_modified = tv->tv_sec;
784 grn_obj_touch(ctx, DB_OBJ(obj)->db, tv);
785 }
786 break;
787 }
788 }
789}
790
791grn_rc
792grn_db_check_name(grn_ctx *ctx, const char *name, unsigned int name_size)
793{
794 int len;
795 const char *name_end = name + name_size;
796 if (name_size > 0 &&
797 *name == GRN_DB_PSEUDO_COLUMN_PREFIX) {
798 return GRN_INVALID_ARGUMENT;
799 }
800 while (name < name_end) {
801 char c = *name;
802 if ((unsigned int)((c | 0x20) - 'a') >= 26u &&
803 (unsigned int)(c - '0') >= 10u &&
804 c != '_' &&
805 c != '-' &&
806 c != '#' &&
807 c != '@') {
808 return GRN_INVALID_ARGUMENT;
809 }
810 if (!(len = grn_charlen(ctx, name, name_end))) { break; }
811 name += len;
812 }
813 return GRN_SUCCESS;
814}
815
816static grn_obj *
817grn_type_open(grn_ctx *ctx, grn_obj_spec *spec)
818{
819 struct _grn_type *res;
820 res = GRN_MALLOC(sizeof(struct _grn_type));
821 if (res) {
822 GRN_DB_OBJ_SET_TYPE(res, GRN_TYPE);
823 res->obj.header = spec->header;
824 GRN_TYPE_SIZE(&res->obj) = GRN_TYPE_SIZE(spec);
825 }
826 return (grn_obj *)res;
827}
828
829grn_obj *
830grn_proc_create(grn_ctx *ctx, const char *name, int name_size, grn_proc_type type,
831 grn_proc_func *init, grn_proc_func *next, grn_proc_func *fin,
832 unsigned int nvars, grn_expr_var *vars)
833{
834 grn_proc *res = NULL;
835 grn_id id = GRN_ID_NIL;
836 grn_id range = GRN_ID_NIL;
837 int added = 0;
838 grn_obj *db;
839 const char *path;
840 if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
841 ERR(GRN_INVALID_ARGUMENT, "db not initialized");
842 return NULL;
843 }
844 GRN_API_ENTER;
845 path = ctx->impl->plugin_path;
846 if (path) {
847 range = grn_plugin_reference(ctx, path);
848 }
849 if (name_size < 0) {
850 name_size = strlen(name);
851 }
852 if (grn_db_check_name(ctx, name, name_size)) {
853 GRN_DB_CHECK_NAME_ERR("[proc][create]", name, name_size);
854 GRN_API_RETURN(NULL);
855 }
856 if (!GRN_DB_P(db)) {
857 ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
858 GRN_API_RETURN(NULL);
859 }
860 if (name && name_size) {
861 grn_db *s = (grn_db *)db;
862 if (!(id = grn_table_get(ctx, s->keys, name, name_size))) {
863 if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
864 ERR(GRN_NO_MEMORY_AVAILABLE, "grn_table_add failed");
865 GRN_API_RETURN(NULL);
866 }
867 }
868 if (!added) {
869 db_value *vp;
870 if ((vp = grn_tiny_array_at(&s->values, id)) && (res = (grn_proc *)vp->ptr)) {
871 /* TODO: Do more robust check. */
872 if (res->funcs[PROC_INIT] ||
873 res->funcs[PROC_NEXT] ||
874 res->funcs[PROC_FIN]) {
875 ERR(GRN_INVALID_ARGUMENT, "already used name");
876 GRN_API_RETURN(NULL);
877 }
878 if (range != GRN_ID_NIL) {
879 grn_plugin_close(ctx, range);
880 }
881 GRN_API_RETURN((grn_obj *)res);
882 } else {
883 added = 1;
884 }
885 }
886 } else if (ctx->impl && ctx->impl->values) {
887 id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
888 added = 1;
889 }
890 if (!res) { res = GRN_MALLOCN(grn_proc, 1); }
891 if (res) {
892 GRN_DB_OBJ_SET_TYPE(res, GRN_PROC);
893 res->obj.db = db;
894 res->obj.id = id;
895 res->obj.header.domain = GRN_ID_NIL;
896 res->obj.header.flags = path ? GRN_OBJ_CUSTOM_NAME : 0;
897 res->obj.range = range;
898 res->type = type;
899 res->funcs[PROC_INIT] = init;
900 res->funcs[PROC_NEXT] = next;
901 res->funcs[PROC_FIN] = fin;
902 memset(&(res->callbacks), 0, sizeof(res->callbacks));
903 res->callbacks.function.selector_op = GRN_OP_NOP;
904 res->callbacks.function.is_stable = GRN_TRUE;
905 GRN_TEXT_INIT(&res->name_buf, 0);
906 res->vars = NULL;
907 res->nvars = 0;
908 if (added) {
909 if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
910 // grn_obj_delete(ctx, db, id);
911 GRN_FREE(res);
912 GRN_API_RETURN(NULL);
913 }
914 }
915 while (nvars--) {
916 grn_obj *v = grn_expr_add_var(ctx, (grn_obj *)res, vars->name, vars->name_size);
917 GRN_OBJ_INIT(v, vars->value.header.type, 0, vars->value.header.domain);
918 GRN_TEXT_PUT(ctx, v, GRN_TEXT_VALUE(&vars->value), GRN_TEXT_LEN(&vars->value));
919 vars++;
920 }
921 }
922 GRN_API_RETURN((grn_obj *)res);
923}
924
925/* grn_table */
926
927static void
928calc_rec_size(grn_table_flags flags, uint32_t max_n_subrecs, uint32_t range_size,
929 uint32_t additional_value_size,
930 uint8_t *subrec_size, uint8_t *subrec_offset,
931 uint32_t *key_size, uint32_t *value_size)
932{
933 *subrec_size = 0;
934 *subrec_offset = 0;
935 if (flags & GRN_OBJ_WITH_SUBREC) {
936 switch (flags & GRN_OBJ_UNIT_MASK) {
937 case GRN_OBJ_UNIT_DOCUMENT_NONE :
938 break;
939 case GRN_OBJ_UNIT_DOCUMENT_SECTION :
940 *subrec_offset = sizeof(grn_id);
941 *subrec_size = sizeof(uint32_t);
942 break;
943 case GRN_OBJ_UNIT_DOCUMENT_POSITION :
944 *subrec_offset = sizeof(grn_id);
945 *subrec_size = sizeof(uint32_t) + sizeof(uint32_t);
946 break;
947 case GRN_OBJ_UNIT_SECTION_NONE :
948 *key_size += sizeof(uint32_t);
949 break;
950 case GRN_OBJ_UNIT_SECTION_POSITION :
951 *key_size += sizeof(uint32_t);
952 *subrec_offset = sizeof(grn_id) + sizeof(uint32_t);
953 *subrec_size = sizeof(uint32_t);
954 break;
955 case GRN_OBJ_UNIT_POSITION_NONE :
956 *key_size += sizeof(uint32_t) + sizeof(uint32_t);
957 break;
958 case GRN_OBJ_UNIT_USERDEF_DOCUMENT :
959 *subrec_size = range_size;
960 break;
961 case GRN_OBJ_UNIT_USERDEF_SECTION :
962 *subrec_size = range_size + sizeof(uint32_t);
963 break;
964 case GRN_OBJ_UNIT_USERDEF_POSITION :
965 *subrec_size = range_size + sizeof(uint32_t) + sizeof(uint32_t);
966 break;
967 }
968 *value_size = (uintptr_t)GRN_RSET_SUBRECS_NTH((((grn_rset_recinfo *)0)->subrecs),
969 *subrec_size, max_n_subrecs);
970 } else {
971 *value_size = range_size;
972 }
973 *value_size += additional_value_size;
974}
975
976static grn_rc _grn_obj_remove(grn_ctx *ctx, grn_obj *obj, grn_bool dependent);
977
978static grn_rc
979grn_table_create_validate(grn_ctx *ctx, const char *name, unsigned int name_size,
980 const char *path, grn_table_flags flags,
981 grn_obj *key_type, grn_obj *value_type)
982{
983 grn_table_flags table_type;
984 const char *table_type_name = NULL;
985
986 table_type = (flags & GRN_OBJ_TABLE_TYPE_MASK);
987 switch (table_type) {
988 case GRN_OBJ_TABLE_HASH_KEY :
989 table_type_name = "TABLE_HASH_KEY";
990 break;
991 case GRN_OBJ_TABLE_PAT_KEY :
992 table_type_name = "TABLE_PAT_KEY";
993 break;
994 case GRN_OBJ_TABLE_DAT_KEY :
995 table_type_name = "TABLE_DAT_KEY";
996 break;
997 case GRN_OBJ_TABLE_NO_KEY :
998 table_type_name = "TABLE_NO_KEY";
999 break;
1000 default :
1001 table_type_name = "unknown";
1002 break;
1003 }
1004
1005 if (!key_type && table_type != GRN_OBJ_TABLE_NO_KEY &&
1006 !(flags & GRN_OBJ_KEY_VAR_SIZE)) {
1007 ERR(GRN_INVALID_ARGUMENT,
1008 "[table][create] "
1009 "key type is required for TABLE_HASH_KEY, TABLE_PAT_KEY or "
1010 "TABLE_DAT_KEY: <%.*s>", name_size, name);
1011 return ctx->rc;
1012 }
1013
1014 if (key_type && table_type == GRN_OBJ_TABLE_NO_KEY) {
1015 int key_name_size;
1016 char key_name[GRN_TABLE_MAX_KEY_SIZE];
1017 key_name_size = grn_obj_name(ctx, key_type, key_name,
1018 GRN_TABLE_MAX_KEY_SIZE);
1019 ERR(GRN_INVALID_ARGUMENT,
1020 "[table][create] "
1021 "key isn't available for TABLE_NO_KEY table: <%.*s> (%.*s)",
1022 name_size, name, key_name_size, key_name);
1023 return ctx->rc;
1024 }
1025
1026 if ((flags & GRN_OBJ_KEY_WITH_SIS) &&
1027 table_type != GRN_OBJ_TABLE_PAT_KEY) {
1028 ERR(GRN_INVALID_ARGUMENT,
1029 "[table][create] "
1030 "key with SIS is available only for TABLE_PAT_KEY table: "
1031 "<%.*s>(%s)",
1032 name_size, name,
1033 table_type_name);
1034 return ctx->rc;
1035 }
1036
1037 if ((flags & GRN_OBJ_KEY_NORMALIZE) &&
1038 table_type == GRN_OBJ_TABLE_NO_KEY) {
1039 ERR(GRN_INVALID_ARGUMENT,
1040 "[table][create] "
1041 "key normalization isn't available for TABLE_NO_KEY table: <%.*s>",
1042 name_size, name);
1043 return ctx->rc;
1044 }
1045
1046 if ((flags & GRN_OBJ_KEY_LARGE) &&
1047 table_type != GRN_OBJ_TABLE_HASH_KEY) {
1048 ERR(GRN_INVALID_ARGUMENT,
1049 "[table][create] "
1050 "large key support is available only for TABLE_HASH_KEY key table: "
1051 "<%.*s>(%s)",
1052 name_size, name,
1053 table_type_name);
1054 return ctx->rc;
1055 }
1056
1057 return ctx->rc;
1058}
1059
1060static grn_obj *
1061grn_table_create_with_max_n_subrecs(grn_ctx *ctx, const char *name,
1062 unsigned int name_size, const char *path,
1063 grn_table_flags flags, grn_obj *key_type,
1064 grn_obj *value_type,
1065 uint32_t max_n_subrecs,
1066 uint32_t additional_value_size)
1067{
1068 grn_id id;
1069 grn_id domain = GRN_ID_NIL, range = GRN_ID_NIL;
1070 uint32_t key_size, value_size = 0, range_size = 0;
1071 uint8_t subrec_size, subrec_offset;
1072 grn_obj *res = NULL;
1073 grn_obj *db;
1074 char buffer[PATH_MAX];
1075 if (!ctx->impl || !(db = ctx->impl->db)) {
1076 ERR(GRN_INVALID_ARGUMENT, "[table][create] db not initialized");
1077 return NULL;
1078 }
1079 if (grn_db_check_name(ctx, name, name_size)) {
1080 GRN_DB_CHECK_NAME_ERR("[table][create]", name, name_size);
1081 return NULL;
1082 }
1083 if (!GRN_DB_P(db)) {
1084 ERR(GRN_INVALID_ARGUMENT, "[table][create] invalid db assigned");
1085 return NULL;
1086 }
1087 if (grn_table_create_validate(ctx, name, name_size, path, flags,
1088 key_type, value_type)) {
1089 return NULL;
1090 }
1091 if (key_type) {
1092 domain = DB_OBJ(key_type)->id;
1093 switch (key_type->header.type) {
1094 case GRN_TYPE :
1095 {
1096 grn_db_obj *t = (grn_db_obj *)key_type;
1097 flags |= t->header.flags;
1098 key_size = GRN_TYPE_SIZE(t);
1099 if (key_size > GRN_TABLE_MAX_KEY_SIZE) {
1100 int type_name_size;
1101 char type_name[GRN_TABLE_MAX_KEY_SIZE];
1102 type_name_size = grn_obj_name(ctx, key_type, type_name,
1103 GRN_TABLE_MAX_KEY_SIZE);
1104 ERR(GRN_INVALID_ARGUMENT,
1105 "[table][create] key size too big: <%.*s> <%.*s>(%u) (max:%u)",
1106 name_size, name,
1107 type_name_size, type_name,
1108 key_size, GRN_TABLE_MAX_KEY_SIZE);
1109 return NULL;
1110 }
1111 }
1112 break;
1113 case GRN_TABLE_HASH_KEY :
1114 case GRN_TABLE_PAT_KEY :
1115 case GRN_TABLE_DAT_KEY :
1116 case GRN_TABLE_NO_KEY :
1117 key_size = sizeof(grn_id);
1118 break;
1119 default :
1120 {
1121 int key_name_size;
1122 char key_name[GRN_TABLE_MAX_KEY_SIZE];
1123 key_name_size = grn_obj_name(ctx, key_type, key_name,
1124 GRN_TABLE_MAX_KEY_SIZE);
1125 ERR(GRN_INVALID_ARGUMENT,
1126 "[table][create] key type must be type or table: <%.*s> (%.*s)",
1127 name_size, name, key_name_size, key_name);
1128 return NULL;
1129 }
1130 break;
1131 }
1132 } else {
1133 key_size = (flags & GRN_OBJ_KEY_VAR_SIZE) ? GRN_TABLE_MAX_KEY_SIZE : sizeof(grn_id);
1134 }
1135 if (value_type) {
1136 range = DB_OBJ(value_type)->id;
1137 switch (value_type->header.type) {
1138 case GRN_TYPE :
1139 {
1140 grn_db_obj *t = (grn_db_obj *)value_type;
1141 if (t->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
1142 int type_name_size;
1143 char type_name[GRN_TABLE_MAX_KEY_SIZE];
1144 type_name_size = grn_obj_name(ctx, value_type, type_name,
1145 GRN_TABLE_MAX_KEY_SIZE);
1146 ERR(GRN_INVALID_ARGUMENT,
1147 "[table][create] value type must be fixed size: <%.*s> (%.*s)",
1148 name_size, name, type_name_size, type_name);
1149 return NULL;
1150 }
1151 range_size = GRN_TYPE_SIZE(t);
1152 }
1153 break;
1154 case GRN_TABLE_HASH_KEY :
1155 case GRN_TABLE_PAT_KEY :
1156 case GRN_TABLE_DAT_KEY :
1157 case GRN_TABLE_NO_KEY :
1158 range_size = sizeof(grn_id);
1159 break;
1160 default :
1161 {
1162 int value_name_size;
1163 char value_name[GRN_TABLE_MAX_KEY_SIZE];
1164 value_name_size = grn_obj_name(ctx, value_type, value_name,
1165 GRN_TABLE_MAX_KEY_SIZE);
1166 ERR(GRN_INVALID_ARGUMENT,
1167 "[table][create] value type must be type or table: <%.*s> (%.*s)",
1168 name_size, name, value_name_size, value_name);
1169 return NULL;
1170 }
1171 break;
1172 }
1173 }
1174
1175 id = grn_obj_register(ctx, db, name, name_size);
1176 if (ERRP(ctx, GRN_ERROR)) { return NULL; }
1177 if (GRN_OBJ_PERSISTENT & flags) {
1178 GRN_LOG(ctx, GRN_LOG_NOTICE,
1179 "DDL:%u:table_create %.*s", id, name_size, name);
1180 if (!path) {
1181 if (GRN_DB_PERSISTENT_P(db)) {
1182 grn_db_generate_pathname(ctx, db, id, buffer);
1183 path = buffer;
1184 } else {
1185 ERR(GRN_INVALID_ARGUMENT, "path not assigned for persistent table");
1186 grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1187 return NULL;
1188 }
1189 } else {
1190 flags |= GRN_OBJ_CUSTOM_NAME;
1191 }
1192 } else {
1193 if (path) {
1194 ERR(GRN_INVALID_ARGUMENT, "path assigned for temporary table");
1195 grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1196 return NULL;
1197 }
1198 if (GRN_DB_PERSISTENT_P(db) && name && name_size) {
1199 ERR(GRN_INVALID_ARGUMENT, "name assigned for temporary table");
1200 grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1201 return NULL;
1202 }
1203 }
1204 calc_rec_size(flags, max_n_subrecs, range_size, additional_value_size,
1205 &subrec_size, &subrec_offset, &key_size, &value_size);
1206 switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
1207 case GRN_OBJ_TABLE_HASH_KEY :
1208 res = (grn_obj *)grn_hash_create(ctx, path, key_size, value_size, flags);
1209 break;
1210 case GRN_OBJ_TABLE_PAT_KEY :
1211 res = (grn_obj *)grn_pat_create(ctx, path, key_size, value_size, flags);
1212 break;
1213 case GRN_OBJ_TABLE_DAT_KEY :
1214 res = (grn_obj *)grn_dat_create(ctx, path, key_size, value_size, flags);
1215 break;
1216 case GRN_OBJ_TABLE_NO_KEY :
1217 domain = range;
1218 res = (grn_obj *)grn_array_create(ctx, path, value_size, flags);
1219 break;
1220 }
1221 if (res) {
1222 DB_OBJ(res)->header.impl_flags = 0;
1223 DB_OBJ(res)->header.domain = domain;
1224 DB_OBJ(res)->range = range;
1225 DB_OBJ(res)->max_n_subrecs = max_n_subrecs;
1226 DB_OBJ(res)->subrec_size = subrec_size;
1227 DB_OBJ(res)->subrec_offset = subrec_offset;
1228 DB_OBJ(res)->flags.group = 0;
1229 if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
1230 _grn_obj_remove(ctx, res, GRN_FALSE);
1231 res = NULL;
1232 }
1233 } else {
1234 grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
1235 }
1236 return res;
1237}
1238
1239grn_obj *
1240grn_table_create(grn_ctx *ctx, const char *name, unsigned int name_size,
1241 const char *path, grn_table_flags flags,
1242 grn_obj *key_type, grn_obj *value_type)
1243{
1244 grn_obj *res;
1245 GRN_API_ENTER;
1246 res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
1247 flags, key_type, value_type,
1248 0, 0);
1249 GRN_API_RETURN(res);
1250}
1251
1252grn_obj *
1253grn_table_create_for_group(grn_ctx *ctx, const char *name,
1254 unsigned int name_size, const char *path,
1255 grn_obj *group_key, grn_obj *value_type,
1256 unsigned int max_n_subrecs)
1257{
1258 grn_obj *res = NULL;
1259 GRN_API_ENTER;
1260 if (group_key) {
1261 grn_obj *key_type;
1262 key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, group_key));
1263 if (key_type) {
1264 res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
1265 GRN_TABLE_HASH_KEY|
1266 GRN_OBJ_WITH_SUBREC|
1267 GRN_OBJ_UNIT_USERDEF_DOCUMENT,
1268 key_type, value_type,
1269 max_n_subrecs, 0);
1270 grn_obj_unlink(ctx, key_type);
1271 }
1272 } else {
1273 res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
1274 GRN_TABLE_HASH_KEY|
1275 GRN_OBJ_KEY_VAR_SIZE|
1276 GRN_OBJ_WITH_SUBREC|
1277 GRN_OBJ_UNIT_USERDEF_DOCUMENT,
1278 NULL, value_type,
1279 max_n_subrecs, 0);
1280 }
1281 GRN_API_RETURN(res);
1282}
1283
1284unsigned int
1285grn_table_get_subrecs(grn_ctx *ctx, grn_obj *table, grn_id id,
1286 grn_id *subrecbuf, int *scorebuf, int buf_size)
1287{
1288 unsigned int count = 0;
1289 GRN_API_ENTER;
1290 if (GRN_OBJ_TABLEP(table)) {
1291 uint32_t value_size;
1292 grn_rset_recinfo *ri;
1293 uint32_t subrec_size = DB_OBJ(table)->subrec_size;
1294 uint32_t max_n_subrecs = DB_OBJ(table)->max_n_subrecs;
1295 if (subrec_size < sizeof(grn_id)) { goto exit; }
1296 if (!max_n_subrecs) { goto exit; }
1297 ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, table, id, &value_size);
1298 if (ri) {
1299 byte *psubrec = (byte *)ri->subrecs;
1300 uint32_t n_subrecs = (uint32_t)GRN_RSET_N_SUBRECS(ri);
1301 uint32_t limit = value_size / (GRN_RSET_SCORE_SIZE + subrec_size);
1302 if (limit > buf_size) {
1303 limit = buf_size;
1304 }
1305 if (limit > n_subrecs) {
1306 limit = n_subrecs;
1307 }
1308 if (limit > max_n_subrecs) {
1309 limit = max_n_subrecs;
1310 }
1311 for (; count < limit; count++) {
1312 if (scorebuf) {
1313 scorebuf[count] = *((double *)psubrec);
1314 }
1315 psubrec += GRN_RSET_SCORE_SIZE;
1316 if (subrecbuf) {
1317 subrecbuf[count] = *((grn_id *)psubrec);
1318 }
1319 psubrec += subrec_size;
1320 }
1321 }
1322 }
1323exit :
1324 GRN_API_RETURN(count);
1325}
1326
1327grn_obj *
1328grn_table_open(grn_ctx *ctx, const char *name, unsigned int name_size, const char *path)
1329{
1330 grn_obj *db;
1331 if (!ctx->impl || !(db = ctx->impl->db)) {
1332 ERR(GRN_INVALID_ARGUMENT, "db not initialized");
1333 return NULL;
1334 }
1335 GRN_API_ENTER;
1336 if (!GRN_DB_P(db)) {
1337 ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
1338 GRN_API_RETURN(NULL);
1339 } else {
1340 grn_obj *res = grn_ctx_get(ctx, name, name_size);
1341 if (res) {
1342 const char *path2 = grn_obj_path(ctx, res);
1343 if (path && (!path2 || strcmp(path, path2))) {
1344 ERR(GRN_INVALID_ARGUMENT, "path unmatch");
1345 GRN_API_RETURN(NULL);
1346 }
1347 } else if (path) {
1348 uint32_t type = grn_io_detect_type(ctx, path);
1349 if (!type) { GRN_API_RETURN(NULL); }
1350 switch (type) {
1351 case GRN_TABLE_HASH_KEY :
1352 res = (grn_obj *)grn_hash_open(ctx, path);
1353 break;
1354 case GRN_TABLE_PAT_KEY :
1355 res = (grn_obj *)grn_pat_open(ctx, path);
1356 break;
1357 case GRN_TABLE_DAT_KEY :
1358 res = (grn_obj *)grn_dat_open(ctx, path);
1359 break;
1360 case GRN_TABLE_NO_KEY :
1361 res = (grn_obj *)grn_array_open(ctx, path);
1362 break;
1363 }
1364 if (res) {
1365 grn_id id = grn_obj_register(ctx, db, name, name_size);
1366 res->header.flags |= GRN_OBJ_CUSTOM_NAME;
1367 res->header.domain = GRN_ID_NIL; /* unknown */
1368 DB_OBJ(res)->range = GRN_ID_NIL; /* unknown */
1369 grn_db_obj_init(ctx, db, id, DB_OBJ(res));
1370 }
1371 } else {
1372 ERR(GRN_INVALID_ARGUMENT, "path is missing");
1373 }
1374 GRN_API_RETURN(res);
1375 }
1376}
1377
1378grn_id
1379grn_table_lcp_search(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
1380{
1381 grn_id id = GRN_ID_NIL;
1382 GRN_API_ENTER;
1383 switch (table->header.type) {
1384 case GRN_TABLE_PAT_KEY :
1385 {
1386 grn_pat *pat = (grn_pat *)table;
1387 WITH_NORMALIZE(pat, key, key_size, {
1388 id = grn_pat_lcp_search(ctx, pat, key, key_size);
1389 });
1390 }
1391 break;
1392 case GRN_TABLE_DAT_KEY :
1393 {
1394 grn_dat *dat = (grn_dat *)table;
1395 WITH_NORMALIZE(dat, key, key_size, {
1396 id = grn_dat_lcp_search(ctx, dat, key, key_size);
1397 });
1398 }
1399 break;
1400 case GRN_TABLE_HASH_KEY :
1401 {
1402 grn_hash *hash = (grn_hash *)table;
1403 WITH_NORMALIZE(hash, key, key_size, {
1404 id = grn_hash_get(ctx, hash, key, key_size, NULL);
1405 });
1406 }
1407 break;
1408 }
1409 GRN_API_RETURN(id);
1410}
1411
1412grn_obj *
1413grn_obj_default_set_value_hook(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1414{
1415 grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
1416 if (!pctx) {
1417 ERR(GRN_INVALID_ARGUMENT, "default_set_value_hook failed");
1418 } else {
1419 grn_obj *flags = grn_ctx_pop(ctx);
1420 grn_obj *newvalue = grn_ctx_pop(ctx);
1421 grn_obj *oldvalue = grn_ctx_pop(ctx);
1422 grn_obj *id = grn_ctx_pop(ctx);
1423 grn_hook *h = pctx->currh;
1424 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(h);
1425 grn_obj *target = grn_ctx_at(ctx, data->target);
1426 int section = data->section;
1427 if (flags) { /* todo */ }
1428 if (target) {
1429 switch (target->header.type) {
1430 case GRN_COLUMN_INDEX :
1431 grn_ii_column_update(ctx, (grn_ii *)target,
1432 GRN_UINT32_VALUE(id),
1433 section, oldvalue, newvalue, NULL);
1434 }
1435 }
1436 }
1437 return NULL;
1438}
1439
1440grn_id
1441grn_table_add(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size, int *added)
1442{
1443 grn_id id = GRN_ID_NIL;
1444 GRN_API_ENTER;
1445 if (table) {
1446 int added_ = 0;
1447 switch (table->header.type) {
1448 case GRN_TABLE_PAT_KEY :
1449 {
1450 grn_pat *pat = (grn_pat *)table;
1451 WITH_NORMALIZE(pat, key, key_size, {
1452 if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
1453 if (grn_io_lock(ctx, pat->io, grn_lock_timeout)) {
1454 id = GRN_ID_NIL;
1455 } else {
1456 id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
1457 grn_io_unlock(pat->io);
1458 }
1459 } else {
1460 id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
1461 }
1462 });
1463 if (added) { *added = added_; }
1464 }
1465 break;
1466 case GRN_TABLE_DAT_KEY :
1467 {
1468 grn_dat *dat = (grn_dat *)table;
1469 WITH_NORMALIZE(dat, key, key_size, {
1470 if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
1471 if (grn_io_lock(ctx, dat->io, grn_lock_timeout)) {
1472 id = GRN_ID_NIL;
1473 } else {
1474 id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
1475 grn_io_unlock(dat->io);
1476 }
1477 } else {
1478 id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
1479 }
1480 });
1481 if (added) { *added = added_; }
1482 }
1483 break;
1484 case GRN_TABLE_HASH_KEY :
1485 {
1486 grn_hash *hash = (grn_hash *)table;
1487 WITH_NORMALIZE(hash, key, key_size, {
1488 if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
1489 if (grn_io_lock(ctx, hash->io, grn_lock_timeout)) {
1490 id = GRN_ID_NIL;
1491 } else {
1492 id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
1493 grn_io_unlock(hash->io);
1494 }
1495 } else {
1496 id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
1497 }
1498 });
1499 if (added) { *added = added_; }
1500 }
1501 break;
1502 case GRN_TABLE_NO_KEY :
1503 {
1504 grn_array *array = (grn_array *)table;
1505 if (array->io && !(array->io->flags & GRN_IO_TEMPORARY)) {
1506 if (grn_io_lock(ctx, array->io, grn_lock_timeout)) {
1507 id = GRN_ID_NIL;
1508 } else {
1509 id = grn_array_add(ctx, array, NULL);
1510 grn_io_unlock(array->io);
1511 }
1512 } else {
1513 id = grn_array_add(ctx, array, NULL);
1514 }
1515 added_ = id ? 1 : 0;
1516 if (added) { *added = added_; }
1517 }
1518 break;
1519 }
1520 if (added_) {
1521 grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT];
1522 if (hooks) {
1523 // todo : grn_proc_ctx_open()
1524 grn_obj id_, flags_, oldvalue_, value_;
1525 grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
1526 GRN_UINT32_INIT(&id_, 0);
1527 GRN_UINT32_INIT(&flags_, 0);
1528 GRN_TEXT_INIT(&oldvalue_, 0);
1529 GRN_TEXT_INIT(&value_, GRN_OBJ_DO_SHALLOW_COPY);
1530 GRN_TEXT_SET_REF(&value_, key, key_size);
1531 GRN_UINT32_SET(ctx, &id_, id);
1532 GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
1533 while (hooks) {
1534 grn_ctx_push(ctx, &id_);
1535 grn_ctx_push(ctx, &oldvalue_);
1536 grn_ctx_push(ctx, &value_);
1537 grn_ctx_push(ctx, &flags_);
1538 pctx.caller = NULL;
1539 pctx.currh = hooks;
1540 if (hooks->proc) {
1541 hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
1542 } else {
1543 grn_obj_default_set_value_hook(ctx, 1, &table, &pctx.user_data);
1544 }
1545 if (ctx->rc) { break; }
1546 hooks = hooks->next;
1547 pctx.offset++;
1548 }
1549 }
1550 }
1551 }
1552 GRN_API_RETURN(id);
1553}
1554
1555grn_id
1556grn_table_get_by_key(grn_ctx *ctx, grn_obj *table, grn_obj *key)
1557{
1558 grn_id id = GRN_ID_NIL;
1559 if (table->header.domain == key->header.domain) {
1560 id = grn_table_get(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key));
1561 } else {
1562 grn_rc rc;
1563 grn_obj buf;
1564 GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
1565 if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
1566 grn_obj *domain = grn_ctx_at(ctx, table->header.domain);
1567 ERR_CAST(table, domain, key);
1568 } else {
1569 id = grn_table_get(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1570 }
1571 GRN_OBJ_FIN(ctx, &buf);
1572 }
1573 return id;
1574}
1575
1576grn_id
1577grn_table_add_by_key(grn_ctx *ctx, grn_obj *table, grn_obj *key, int *added)
1578{
1579 grn_id id = GRN_ID_NIL;
1580 if (table->header.domain == key->header.domain) {
1581 id = grn_table_add(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key), added);
1582 } else {
1583 grn_rc rc;
1584 grn_obj buf;
1585 GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
1586 if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
1587 grn_obj *domain = grn_ctx_at(ctx, table->header.domain);
1588 ERR_CAST(table, domain, key);
1589 } else {
1590 id = grn_table_add(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), added);
1591 }
1592 GRN_OBJ_FIN(ctx, &buf);
1593 }
1594 return id;
1595}
1596
1597grn_id
1598grn_table_get(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
1599{
1600 grn_id id = GRN_ID_NIL;
1601 GRN_API_ENTER;
1602 if (table) {
1603 if (table->header.type == GRN_DB) {
1604 grn_db *db = (grn_db *)table;
1605 table = db->keys;
1606 }
1607 switch (table->header.type) {
1608 case GRN_TABLE_PAT_KEY :
1609 WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1610 id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, NULL);
1611 });
1612 break;
1613 case GRN_TABLE_DAT_KEY :
1614 WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1615 id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, NULL);
1616 });
1617 break;
1618 case GRN_TABLE_HASH_KEY :
1619 WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1620 id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, NULL);
1621 });
1622 break;
1623 }
1624 }
1625 GRN_API_RETURN(id);
1626}
1627
1628grn_id
1629grn_table_at(grn_ctx *ctx, grn_obj *table, grn_id id)
1630{
1631 GRN_API_ENTER;
1632 if (table) {
1633 switch (table->header.type) {
1634 case GRN_DB :
1635 {
1636 grn_db *db = (grn_db *)table;
1637 id = grn_table_at(ctx, db->keys, id);
1638 }
1639 break;
1640 case GRN_TABLE_PAT_KEY :
1641 id = grn_pat_at(ctx, (grn_pat *)table, id);
1642 break;
1643 case GRN_TABLE_DAT_KEY :
1644 id = grn_dat_at(ctx, (grn_dat *)table, id);
1645 break;
1646 case GRN_TABLE_HASH_KEY :
1647 id = grn_hash_at(ctx, (grn_hash *)table, id);
1648 break;
1649 case GRN_TABLE_NO_KEY :
1650 id = grn_array_at(ctx, (grn_array *)table, id);
1651 break;
1652 default :
1653 id = GRN_ID_NIL;
1654 }
1655 }
1656 GRN_API_RETURN(id);
1657}
1658
1659inline static grn_id
1660grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1661 void **value, int *added)
1662{
1663 grn_id id = GRN_ID_NIL;
1664 if (!key || !key_size) { return GRN_ID_NIL; }
1665 if (table) {
1666 switch (table->header.type) {
1667 case GRN_TABLE_PAT_KEY :
1668 WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1669 id = grn_pat_add(ctx, (grn_pat *)table, key, key_size, value, added);
1670 });
1671 break;
1672 case GRN_TABLE_DAT_KEY :
1673 WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1674 id = grn_dat_add(ctx, (grn_dat *)table, key, key_size, value, added);
1675 });
1676 break;
1677 case GRN_TABLE_HASH_KEY :
1678 WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1679 id = grn_hash_add(ctx, (grn_hash *)table, key, key_size, value, added);
1680 });
1681 break;
1682 case GRN_TABLE_NO_KEY :
1683 id = grn_array_add(ctx, (grn_array *)table, value);
1684 if (added) { *added = id ? 1 : 0; }
1685 break;
1686 }
1687 }
1688 return id;
1689}
1690
1691grn_id
1692grn_table_add_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1693 void **value, int *added) {
1694 grn_id id;
1695 GRN_API_ENTER;
1696 id = grn_table_add_v_inline(ctx, table, key, key_size, value, added);
1697 GRN_API_RETURN(id);
1698}
1699
1700grn_id
1701grn_table_get_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
1702 void **value)
1703{
1704 grn_id id = GRN_ID_NIL;
1705 GRN_API_ENTER;
1706 if (table) {
1707 switch (table->header.type) {
1708 case GRN_TABLE_PAT_KEY :
1709 WITH_NORMALIZE((grn_pat *)table, key, key_size, {
1710 id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, value);
1711 });
1712 break;
1713 case GRN_TABLE_DAT_KEY :
1714 WITH_NORMALIZE((grn_dat *)table, key, key_size, {
1715 id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, value);
1716 });
1717 break;
1718 case GRN_TABLE_HASH_KEY :
1719 WITH_NORMALIZE((grn_hash *)table, key, key_size, {
1720 id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, value);
1721 });
1722 break;
1723 }
1724 }
1725 GRN_API_RETURN(id);
1726}
1727
1728int
1729grn_table_get_key(grn_ctx *ctx, grn_obj *table, grn_id id, void *keybuf, int buf_size)
1730{
1731 int r = 0;
1732 GRN_API_ENTER;
1733 if (table) {
1734 if (table->header.type == GRN_DB) {
1735 table = ((grn_db *)table)->keys;
1736 }
1737 switch (table->header.type) {
1738 case GRN_TABLE_HASH_KEY :
1739 r = grn_hash_get_key(ctx, (grn_hash *)table, id, keybuf, buf_size);
1740 break;
1741 case GRN_TABLE_PAT_KEY :
1742 r = grn_pat_get_key(ctx, (grn_pat *)table, id, keybuf, buf_size);
1743 break;
1744 case GRN_TABLE_DAT_KEY :
1745 r = grn_dat_get_key(ctx, (grn_dat *)table, id, keybuf, buf_size);
1746 break;
1747 case GRN_TABLE_NO_KEY :
1748 {
1749 grn_array *a = (grn_array *)table;
1750 if (a->obj.header.domain) {
1751 if (buf_size >= a->value_size) {
1752 r = grn_array_get_value(ctx, a, id, keybuf);
1753 } else {
1754 r = a->value_size;
1755 }
1756 }
1757 }
1758 break;
1759 }
1760 }
1761 GRN_API_RETURN(r);
1762}
1763
1764int
1765grn_table_get_key2(grn_ctx *ctx, grn_obj *table, grn_id id, grn_obj *bulk)
1766{
1767 int r = 0;
1768 GRN_API_ENTER;
1769 if (table) {
1770 if (table->header.type == GRN_DB) {
1771 table = ((grn_db *)table)->keys;
1772 }
1773 switch (table->header.type) {
1774 case GRN_TABLE_HASH_KEY :
1775 r = grn_hash_get_key2(ctx, (grn_hash *)table, id, bulk);
1776 break;
1777 case GRN_TABLE_PAT_KEY :
1778 r = grn_pat_get_key2(ctx, (grn_pat *)table, id, bulk);
1779 break;
1780 case GRN_TABLE_DAT_KEY :
1781 r = grn_dat_get_key2(ctx, (grn_dat *)table, id, bulk);
1782 break;
1783 case GRN_TABLE_NO_KEY :
1784 {
1785 grn_array *a = (grn_array *)table;
1786 if (a->obj.header.domain) {
1787 if (!grn_bulk_space(ctx, bulk, a->value_size)) {
1788 char *curr = GRN_BULK_CURR(bulk);
1789 r = grn_array_get_value(ctx, a, id, curr - a->value_size);
1790 }
1791 }
1792 }
1793 break;
1794 }
1795 }
1796 GRN_API_RETURN(r);
1797}
1798
1799static grn_rc
1800grn_obj_clear_value(grn_ctx *ctx, grn_obj *obj, grn_id id)
1801{
1802 grn_rc rc = GRN_SUCCESS;
1803 if (GRN_DB_OBJP(obj)) {
1804 grn_obj buf;
1805 grn_id range = DB_OBJ(obj)->range;
1806 GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
1807 switch (obj->header.type) {
1808 case GRN_COLUMN_VAR_SIZE :
1809 case GRN_COLUMN_FIX_SIZE :
1810 rc = grn_obj_set_value(ctx, obj, id, &buf, GRN_OBJ_SET);
1811 break;
1812 }
1813 GRN_OBJ_FIN(ctx, &buf);
1814 }
1815 return rc;
1816}
1817
1818static void
1819call_delete_hook(grn_ctx *ctx, grn_obj *table, grn_id rid, const void *key, unsigned int key_size)
1820{
1821 if (rid) {
1822 grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_DELETE];
1823 if (hooks) {
1824 // todo : grn_proc_ctx_open()
1825 grn_obj id_, flags_, oldvalue_, value_;
1826 grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
1827 GRN_UINT32_INIT(&id_, 0);
1828 GRN_UINT32_INIT(&flags_, 0);
1829 GRN_TEXT_INIT(&oldvalue_, GRN_OBJ_DO_SHALLOW_COPY);
1830 GRN_TEXT_INIT(&value_, 0);
1831 GRN_TEXT_SET_REF(&oldvalue_, key, key_size);
1832 GRN_UINT32_SET(ctx, &id_, rid);
1833 GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
1834 while (hooks) {
1835 grn_ctx_push(ctx, &id_);
1836 grn_ctx_push(ctx, &oldvalue_);
1837 grn_ctx_push(ctx, &value_);
1838 grn_ctx_push(ctx, &flags_);
1839 pctx.caller = NULL;
1840 pctx.currh = hooks;
1841 if (hooks->proc) {
1842 hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
1843 } else {
1844 grn_obj_default_set_value_hook(ctx, 1, &table, &pctx.user_data);
1845 }
1846 if (ctx->rc) { break; }
1847 hooks = hooks->next;
1848 pctx.offset++;
1849 }
1850 }
1851 }
1852}
1853
1854static void
1855clear_column_values(grn_ctx *ctx, grn_obj *table, grn_id rid)
1856{
1857 if (rid) {
1858 grn_hash *cols;
1859 if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1860 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
1861 if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
1862 grn_id *key;
1863 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
1864 grn_obj *col = grn_ctx_at(ctx, *key);
1865 if (col) { grn_obj_clear_value(ctx, col, rid); }
1866 });
1867 }
1868 grn_hash_close(ctx, cols);
1869 }
1870 }
1871}
1872
1873static void
1874delete_reference_records_in_index(grn_ctx *ctx, grn_obj *table, grn_id id,
1875 grn_obj *index)
1876{
1877 grn_ii *ii = (grn_ii *)index;
1878 grn_ii_cursor *ii_cursor = NULL;
1879 grn_posting *posting;
1880 grn_obj source_ids;
1881 unsigned int i, n_ids;
1882 grn_obj sources;
1883 grn_bool have_reference_source = GRN_FALSE;
1884
1885 GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
1886 GRN_PTR_INIT(&sources, GRN_OBJ_VECTOR, 0);
1887
1888 grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
1889 n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
1890 if (n_ids == 0) {
1891 goto exit;
1892 }
1893
1894 for (i = 0; i < n_ids; i++) {
1895 grn_id source_id;
1896 grn_obj *source;
1897
1898 source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
1899 source = grn_ctx_at(ctx, source_id);
1900 if (grn_obj_get_range(ctx, source) == index->header.domain) {
1901 GRN_PTR_PUT(ctx, &sources, source);
1902 have_reference_source = GRN_TRUE;
1903 } else {
1904 grn_obj_unlink(ctx, source);
1905 GRN_PTR_PUT(ctx, &sources, NULL);
1906 }
1907 }
1908
1909 if (!have_reference_source) {
1910 goto exit;
1911 }
1912
1913 ii_cursor = grn_ii_cursor_open(ctx, ii, id, GRN_ID_NIL, GRN_ID_MAX,
1914 ii->n_elements, 0);
1915 if (!ii_cursor) {
1916 goto exit;
1917 }
1918
1919 while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
1920 grn_obj *source = GRN_PTR_VALUE_AT(&sources, posting->sid - 1);
1921 if (!source) {
1922 continue;
1923 }
1924 switch (source->header.type) {
1925 case GRN_COLUMN_VAR_SIZE :
1926 switch (source->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
1927 case GRN_OBJ_COLUMN_SCALAR :
1928 grn_obj_clear_value(ctx, source, posting->rid);
1929 break;
1930 case GRN_OBJ_COLUMN_VECTOR :
1931 {
1932 grn_obj value;
1933 grn_obj new_value;
1934 GRN_TEXT_INIT(&value, 0);
1935 grn_obj_get_value(ctx, source, posting->rid, &value);
1936 if (value.header.type == GRN_UVECTOR) {
1937 int i, n_ids;
1938 GRN_RECORD_INIT(&new_value, GRN_OBJ_VECTOR, value.header.domain);
1939 n_ids = GRN_BULK_VSIZE(&value) / sizeof(grn_id);
1940 for (i = 0; i < n_ids; i++) {
1941 grn_id reference_id = GRN_RECORD_VALUE_AT(&value, i);
1942 if (reference_id == id) {
1943 continue;
1944 }
1945 GRN_RECORD_PUT(ctx, &new_value, reference_id);
1946 }
1947 } else {
1948 unsigned int i, n_elements;
1949 GRN_TEXT_INIT(&new_value, GRN_OBJ_VECTOR);
1950 n_elements = grn_vector_size(ctx, &value);
1951 for (i = 0; i < n_elements; i++) {
1952 const char *content;
1953 unsigned int content_length;
1954 unsigned int weight;
1955 grn_id domain;
1956 content_length =
1957 grn_vector_get_element(ctx, &value, i,
1958 &content, &weight, &domain);
1959 if (grn_table_get(ctx, table, content, content_length) == id) {
1960 continue;
1961 }
1962 grn_vector_add_element(ctx, &new_value, content, content_length,
1963 weight, domain);
1964 }
1965 }
1966 grn_obj_set_value(ctx, source, posting->rid, &new_value,
1967 GRN_OBJ_SET);
1968 GRN_OBJ_FIN(ctx, &new_value);
1969 GRN_OBJ_FIN(ctx, &value);
1970 }
1971 break;
1972 }
1973 break;
1974 case GRN_COLUMN_FIX_SIZE :
1975 grn_obj_clear_value(ctx, source, posting->rid);
1976 break;
1977 }
1978 }
1979
1980exit:
1981 if (ii_cursor) {
1982 grn_ii_cursor_close(ctx, ii_cursor);
1983 }
1984 grn_obj_unlink(ctx, &source_ids);
1985 {
1986 int i, n_sources;
1987 n_sources = GRN_BULK_VSIZE(&sources) / sizeof(grn_obj *);
1988 for (i = 0; i < n_sources; i++) {
1989 grn_obj *source = GRN_PTR_VALUE_AT(&sources, i);
1990 grn_obj_unlink(ctx, source);
1991 }
1992 grn_obj_unlink(ctx, &sources);
1993 }
1994}
1995
1996static grn_rc
1997delete_reference_records(grn_ctx *ctx, grn_obj *table, grn_id id)
1998{
1999 grn_hash *cols;
2000 grn_id *key;
2001
2002 cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
2003 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
2004 if (!cols) {
2005 return ctx->rc;
2006 }
2007
2008 if (!grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
2009 grn_hash_close(ctx, cols);
2010 return ctx->rc;
2011 }
2012
2013 GRN_HASH_EACH(ctx, cols, tid, &key, NULL, NULL, {
2014 grn_obj *col = grn_ctx_at(ctx, *key);
2015 if (!col) {
2016 continue;
2017 }
2018 if (col->header.type != GRN_COLUMN_INDEX) {
2019 continue;
2020 }
2021 delete_reference_records_in_index(ctx, table, id, col);
2022 if (ctx->rc != GRN_SUCCESS) {
2023 break;
2024 }
2025 });
2026
2027 grn_hash_close(ctx, cols);
2028
2029 return ctx->rc;
2030}
2031
2032static grn_rc
2033grn_table_delete_prepare(grn_ctx *ctx, grn_obj *table,
2034 grn_id id, const void *key, unsigned int key_size)
2035{
2036 grn_rc rc;
2037
2038 rc = delete_reference_records(ctx, table, id);
2039 if (rc != GRN_SUCCESS) {
2040 return rc;
2041 }
2042 call_delete_hook(ctx, table, id, key, key_size);
2043 clear_column_values(ctx, table, id);
2044
2045 return rc;
2046}
2047
2048grn_rc
2049grn_table_delete(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
2050{
2051 grn_id rid = GRN_ID_NIL;
2052 grn_rc rc = GRN_INVALID_ARGUMENT;
2053 GRN_API_ENTER;
2054 if (table) {
2055 if (key && key_size) { rid = grn_table_get(ctx, table, key, key_size); }
2056 if (rid) {
2057 rc = grn_table_delete_prepare(ctx, table, rid, key, key_size);
2058 if (rc != GRN_SUCCESS) {
2059 goto exit;
2060 }
2061 switch (table->header.type) {
2062 case GRN_DB :
2063 /* todo : delete tables and columns from db */
2064 break;
2065 case GRN_TABLE_PAT_KEY :
2066 WITH_NORMALIZE((grn_pat *)table, key, key_size, {
2067 grn_pat *pat = (grn_pat *)table;
2068 if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
2069 if (!(rc = grn_io_lock(ctx, pat->io, grn_lock_timeout))) {
2070 rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
2071 grn_io_unlock(pat->io);
2072 }
2073 } else {
2074 rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
2075 }
2076 });
2077 break;
2078 case GRN_TABLE_DAT_KEY :
2079 WITH_NORMALIZE((grn_dat *)table, key, key_size, {
2080 grn_dat *dat = (grn_dat *)table;
2081 if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
2082 if (!(rc = grn_io_lock(ctx, dat->io, grn_lock_timeout))) {
2083 rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
2084 grn_io_unlock(dat->io);
2085 }
2086 } else {
2087 rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
2088 }
2089 });
2090 break;
2091 case GRN_TABLE_HASH_KEY :
2092 WITH_NORMALIZE((grn_hash *)table, key, key_size, {
2093 grn_hash *hash = (grn_hash *)table;
2094 if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
2095 if (!(rc = grn_io_lock(ctx, hash->io, grn_lock_timeout))) {
2096 rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
2097 grn_io_unlock(hash->io);
2098 }
2099 } else {
2100 rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
2101 }
2102 });
2103 break;
2104 }
2105 if (rc == GRN_SUCCESS) {
2106 grn_obj_touch(ctx, table, NULL);
2107 }
2108 }
2109 }
2110exit :
2111 GRN_API_RETURN(rc);
2112}
2113
2114grn_rc
2115_grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
2116 grn_table_delete_optarg *optarg)
2117{
2118 grn_rc rc = GRN_INVALID_ARGUMENT;
2119 if (table) {
2120 if (id) {
2121 const void *key = NULL;
2122 unsigned int key_size = 0;
2123
2124 if (table->header.type != GRN_TABLE_NO_KEY) {
2125 key = _grn_table_key(ctx, table, id, &key_size);
2126 }
2127 rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2128 if (rc != GRN_SUCCESS) {
2129 goto exit;
2130 }
2131 // todo : support optarg
2132 switch (table->header.type) {
2133 case GRN_TABLE_PAT_KEY :
2134 rc = grn_pat_delete_by_id(ctx, (grn_pat *)table, id, optarg);
2135 break;
2136 case GRN_TABLE_DAT_KEY :
2137 rc = grn_dat_delete_by_id(ctx, (grn_dat *)table, id, optarg);
2138 break;
2139 case GRN_TABLE_HASH_KEY :
2140 rc = grn_hash_delete_by_id(ctx, (grn_hash *)table, id, optarg);
2141 break;
2142 case GRN_TABLE_NO_KEY :
2143 rc = grn_array_delete_by_id(ctx, (grn_array *)table, id, optarg);
2144 break;
2145 }
2146 }
2147 }
2148exit :
2149 return rc;
2150}
2151
2152grn_rc
2153grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id)
2154{
2155 grn_rc rc;
2156 grn_io *io;
2157 GRN_API_ENTER;
2158 if ((io = grn_obj_get_io(ctx, table)) && !(io->flags & GRN_IO_TEMPORARY)) {
2159 if (!(rc = grn_io_lock(ctx, io, grn_lock_timeout))) {
2160 rc = _grn_table_delete_by_id(ctx, table, id, NULL);
2161 grn_io_unlock(io);
2162 }
2163 } else {
2164 rc = _grn_table_delete_by_id(ctx, table, id, NULL);
2165 }
2166 if (rc == GRN_SUCCESS) {
2167 grn_obj_touch(ctx, table, NULL);
2168 }
2169 GRN_API_RETURN(rc);
2170}
2171
2172grn_rc grn_ja_truncate(grn_ctx *ctx, grn_ja *ja);
2173grn_rc grn_ra_truncate(grn_ctx *ctx, grn_ra *ra);
2174
2175grn_rc
2176grn_column_truncate(grn_ctx *ctx, grn_obj *column)
2177{
2178 grn_rc rc = GRN_INVALID_ARGUMENT;
2179 GRN_API_ENTER;
2180 if (column) {
2181 grn_hook *hooks;
2182 switch (column->header.type) {
2183 case GRN_COLUMN_INDEX :
2184 rc = grn_ii_truncate(ctx, (grn_ii *)column);
2185 break;
2186 case GRN_COLUMN_VAR_SIZE :
2187 for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
2188 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2189 grn_obj *target = grn_ctx_at(ctx, data->target);
2190 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2191 if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2192 }
2193 rc = grn_ja_truncate(ctx, (grn_ja *)column);
2194 break;
2195 case GRN_COLUMN_FIX_SIZE :
2196 for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
2197 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2198 grn_obj *target = grn_ctx_at(ctx, data->target);
2199 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2200 if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2201 }
2202 rc = grn_ra_truncate(ctx, (grn_ra *)column);
2203 break;
2204 }
2205 if (rc == GRN_SUCCESS) {
2206 grn_obj_touch(ctx, column, NULL);
2207 }
2208 }
2209exit :
2210 GRN_API_RETURN(rc);
2211}
2212
2213grn_rc
2214grn_table_truncate(grn_ctx *ctx, grn_obj *table)
2215{
2216 grn_rc rc = GRN_INVALID_ARGUMENT;
2217 GRN_API_ENTER;
2218 if (table) {
2219 grn_hook *hooks;
2220 grn_hash *cols;
2221 grn_obj *tokenizer;
2222 grn_obj *normalizer;
2223 grn_obj token_filters;
2224 if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
2225 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
2226 if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
2227 grn_id *key;
2228 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
2229 grn_obj *col = grn_ctx_at(ctx, *key);
2230 if (col) { grn_column_truncate(ctx, col); }
2231 });
2232 }
2233 grn_hash_close(ctx, cols);
2234 }
2235 if (table->header.type != GRN_TABLE_NO_KEY) {
2236 grn_table_get_info(ctx, table, NULL, NULL, &tokenizer, &normalizer, NULL);
2237 GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, GRN_ID_NIL);
2238 grn_obj_get_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
2239 }
2240 switch (table->header.type) {
2241 case GRN_TABLE_PAT_KEY :
2242 for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
2243 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2244 grn_obj *target = grn_ctx_at(ctx, data->target);
2245 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2246 if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2247 }
2248 rc = grn_pat_truncate(ctx, (grn_pat *)table);
2249 break;
2250 case GRN_TABLE_DAT_KEY :
2251 for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
2252 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2253 grn_obj *target = grn_ctx_at(ctx, data->target);
2254 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2255 if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2256 }
2257 rc = grn_dat_truncate(ctx, (grn_dat *)table);
2258 break;
2259 case GRN_TABLE_HASH_KEY :
2260 for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
2261 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
2262 grn_obj *target = grn_ctx_at(ctx, data->target);
2263 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
2264 if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
2265 }
2266 rc = grn_hash_truncate(ctx, (grn_hash *)table);
2267 break;
2268 case GRN_TABLE_NO_KEY :
2269 rc = grn_array_truncate(ctx, (grn_array *)table);
2270 break;
2271 }
2272 if (table->header.type != GRN_TABLE_NO_KEY) {
2273 grn_obj_set_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
2274 grn_obj_set_info(ctx, table, GRN_INFO_NORMALIZER, normalizer);
2275 grn_obj_set_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
2276 GRN_OBJ_FIN(ctx, &token_filters);
2277 }
2278 if (rc == GRN_SUCCESS) {
2279 grn_obj_touch(ctx, table, NULL);
2280 }
2281 }
2282exit :
2283 GRN_API_RETURN(rc);
2284}
2285
2286grn_rc
2287grn_table_get_info(grn_ctx *ctx, grn_obj *table, grn_table_flags *flags,
2288 grn_encoding *encoding, grn_obj **tokenizer,
2289 grn_obj **normalizer,
2290 grn_obj **token_filters)
2291{
2292 grn_rc rc = GRN_INVALID_ARGUMENT;
2293 GRN_API_ENTER;
2294 if (table) {
2295 switch (table->header.type) {
2296 case GRN_TABLE_PAT_KEY :
2297 if (flags) { *flags = ((grn_pat *)table)->header->flags; }
2298 if (encoding) { *encoding = ((grn_pat *)table)->encoding; }
2299 if (tokenizer) { *tokenizer = ((grn_pat *)table)->tokenizer; }
2300 if (normalizer) { *normalizer = ((grn_pat *)table)->normalizer; }
2301 if (token_filters) { *token_filters = &(((grn_pat *)table)->token_filters); }
2302 rc = GRN_SUCCESS;
2303 break;
2304 case GRN_TABLE_DAT_KEY :
2305 if (flags) { *flags = ((grn_dat *)table)->header->flags; }
2306 if (encoding) { *encoding = ((grn_dat *)table)->encoding; }
2307 if (tokenizer) { *tokenizer = ((grn_dat *)table)->tokenizer; }
2308 if (normalizer) { *normalizer = ((grn_dat *)table)->normalizer; }
2309 if (token_filters) { *token_filters = &(((grn_dat *)table)->token_filters); }
2310 rc = GRN_SUCCESS;
2311 break;
2312 case GRN_TABLE_HASH_KEY :
2313 if (flags) { *flags = ((grn_hash *)table)->header.common->flags; }
2314 if (encoding) { *encoding = ((grn_hash *)table)->encoding; }
2315 if (tokenizer) { *tokenizer = ((grn_hash *)table)->tokenizer; }
2316 if (normalizer) { *normalizer = ((grn_hash *)table)->normalizer; }
2317 if (token_filters) { *token_filters = &(((grn_hash *)table)->token_filters); }
2318 rc = GRN_SUCCESS;
2319 break;
2320 case GRN_TABLE_NO_KEY :
2321 if (flags) { *flags = grn_array_get_flags(ctx, ((grn_array *)table)); }
2322 if (encoding) { *encoding = GRN_ENC_NONE; }
2323 if (tokenizer) { *tokenizer = NULL; }
2324 if (normalizer) { *normalizer = NULL; }
2325 if (token_filters) { *token_filters = NULL; }
2326 rc = GRN_SUCCESS;
2327 break;
2328 }
2329 }
2330 GRN_API_RETURN(rc);
2331}
2332
2333unsigned int
2334grn_table_size(grn_ctx *ctx, grn_obj *table)
2335{
2336 unsigned int n = 0;
2337 GRN_API_ENTER;
2338 if (table) {
2339 switch (table->header.type) {
2340 case GRN_DB :
2341 n = grn_table_size(ctx, ((grn_db *)table)->keys);
2342 break;
2343 case GRN_TABLE_PAT_KEY :
2344 n = grn_pat_size(ctx, (grn_pat *)table);
2345 break;
2346 case GRN_TABLE_DAT_KEY :
2347 n = grn_dat_size(ctx, (grn_dat *)table);
2348 break;
2349 case GRN_TABLE_HASH_KEY :
2350 n = grn_hash_size(ctx, (grn_hash *)table);
2351 break;
2352 case GRN_TABLE_NO_KEY :
2353 n = grn_array_size(ctx, (grn_array *)table);
2354 break;
2355 default :
2356 ERR(GRN_INVALID_ARGUMENT, "not supported");
2357 break;
2358 }
2359 } else {
2360 ERR(GRN_INVALID_ARGUMENT, "invalid table assigned");
2361 }
2362 GRN_API_RETURN(n);
2363}
2364
2365inline static void
2366subrecs_push(byte *subrecs, int size, int n_subrecs, double score, void *body, int dir)
2367{
2368 byte *v;
2369 double *c2;
2370 int n = n_subrecs - 1, n2;
2371 while (n) {
2372 n2 = (n - 1) >> 1;
2373 c2 = GRN_RSET_SUBRECS_NTH(subrecs,size,n2);
2374 if (GRN_RSET_SUBRECS_CMP(score, *c2, dir) >= 0) { break; }
2375 GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2376 n = n2;
2377 }
2378 v = subrecs + n * (GRN_RSET_SCORE_SIZE + size);
2379 *((double *)v) = score;
2380 grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
2381}
2382
2383inline static void
2384subrecs_replace_min(byte *subrecs, int size, int n_subrecs, double score, void *body, int dir)
2385{
2386 byte *v;
2387 int n = 0, n1, n2;
2388 double *c1, *c2;
2389 for (;;) {
2390 n1 = n * 2 + 1;
2391 n2 = n1 + 1;
2392 c1 = n1 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n1) : NULL;
2393 c2 = n2 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n2) : NULL;
2394 if (c1 && GRN_RSET_SUBRECS_CMP(score, *c1, dir) > 0) {
2395 if (c2 &&
2396 GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0 &&
2397 GRN_RSET_SUBRECS_CMP(*c1, *c2, dir) > 0) {
2398 GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2399 n = n2;
2400 } else {
2401 GRN_RSET_SUBRECS_COPY(subrecs,size,n,c1);
2402 n = n1;
2403 }
2404 } else {
2405 if (c2 && GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) {
2406 GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
2407 n = n2;
2408 } else {
2409 break;
2410 }
2411 }
2412 }
2413 v = subrecs + n * (GRN_RSET_SCORE_SIZE + size);
2414 grn_memcpy(v, &score, GRN_RSET_SCORE_SIZE);
2415 grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
2416}
2417
2418inline static void
2419grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, double score,
2420 grn_rset_posinfo *pi, int dir)
2421{
2422 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
2423 int limit = DB_OBJ(table)->max_n_subrecs;
2424 ri->score += score;
2425 ri->n_subrecs += 1;
2426 if (limit) {
2427 int subrec_size = DB_OBJ(table)->subrec_size;
2428 int n_subrecs = GRN_RSET_N_SUBRECS(ri);
2429 if (pi) {
2430 byte *body = (byte *)pi + DB_OBJ(table)->subrec_offset;
2431 if (limit < n_subrecs) {
2432 if (GRN_RSET_SUBRECS_CMP(score, *((double *)(ri->subrecs)), dir) > 0) {
2433 subrecs_replace_min((byte *)ri->subrecs, subrec_size, limit, score, body, dir);
2434 }
2435 } else {
2436 subrecs_push((byte *)ri->subrecs, subrec_size, n_subrecs, score, body, dir);
2437 }
2438 }
2439 }
2440 }
2441}
2442
2443void
2444grn_table_add_subrec(grn_obj *table, grn_rset_recinfo *ri, double score,
2445 grn_rset_posinfo *pi, int dir)
2446{
2447 grn_table_add_subrec_inline(table, ri, score, pi, dir);
2448}
2449
2450grn_table_cursor *
2451grn_table_cursor_open(grn_ctx *ctx, grn_obj *table,
2452 const void *min, unsigned int min_size,
2453 const void *max, unsigned int max_size,
2454 int offset, int limit, int flags)
2455{
2456 grn_rc rc;
2457 grn_table_cursor *tc = NULL;
2458 unsigned int table_size;
2459 if (!table) { return tc; }
2460 GRN_API_ENTER;
2461 table_size = grn_table_size(ctx, table);
2462 if (flags & GRN_CURSOR_PREFIX) {
2463 if (offset < 0) {
2464 ERR(GRN_TOO_SMALL_OFFSET,
2465 "can't use negative offset with GRN_CURSOR_PREFIX: %d", offset);
2466 } else if (offset != 0 && offset >= table_size) {
2467 ERR(GRN_TOO_LARGE_OFFSET,
2468 "offset is not less than table size: offset:%d, table_size:%d",
2469 offset, table_size);
2470 } else {
2471 if (limit < -1) {
2472 ERR(GRN_TOO_SMALL_LIMIT,
2473 "can't use smaller limit than -1 with GRN_CURSOR_PREFIX: %d",
2474 limit);
2475 } else if (limit == -1) {
2476 limit = table_size;
2477 }
2478 }
2479 } else {
2480 rc = grn_normalize_offset_and_limit(ctx, table_size, &offset, &limit);
2481 if (rc) {
2482 ERR(rc, "grn_normalize_offset_and_limit failed");
2483 }
2484 }
2485 if (!ctx->rc) {
2486 if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
2487 switch (table->header.type) {
2488 case GRN_TABLE_PAT_KEY :
2489 {
2490 grn_pat *pat = (grn_pat *)table;
2491 WITH_NORMALIZE(pat, min, min_size, {
2492 WITH_NORMALIZE(pat, max, max_size, {
2493 grn_pat_cursor *pat_cursor;
2494 pat_cursor = grn_pat_cursor_open(ctx, pat,
2495 min, min_size,
2496 max, max_size,
2497 offset, limit, flags);
2498 tc = (grn_table_cursor *)pat_cursor;
2499 });
2500 });
2501 }
2502 break;
2503 case GRN_TABLE_DAT_KEY :
2504 {
2505 grn_dat *dat = (grn_dat *)table;
2506 WITH_NORMALIZE(dat, min, min_size, {
2507 WITH_NORMALIZE(dat, max, max_size, {
2508 grn_dat_cursor *dat_cursor;
2509 dat_cursor = grn_dat_cursor_open(ctx, dat,
2510 min, min_size,
2511 max, max_size,
2512 offset, limit, flags);
2513 tc = (grn_table_cursor *)dat_cursor;
2514 });
2515 });
2516 }
2517 break;
2518 case GRN_TABLE_HASH_KEY :
2519 {
2520 grn_hash *hash = (grn_hash *)table;
2521 WITH_NORMALIZE(hash, min, min_size, {
2522 WITH_NORMALIZE(hash, max, max_size, {
2523 grn_hash_cursor *hash_cursor;
2524 hash_cursor = grn_hash_cursor_open(ctx, hash,
2525 min, min_size,
2526 max, max_size,
2527 offset, limit, flags);
2528 tc = (grn_table_cursor *)hash_cursor;
2529 });
2530 });
2531 }
2532 break;
2533 case GRN_TABLE_NO_KEY :
2534 tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
2535 GRN_ID_NIL, GRN_ID_NIL,
2536 offset, limit, flags);
2537 break;
2538 }
2539 }
2540 if (tc) {
2541 grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
2542 DB_OBJ(tc)->header.domain = GRN_ID_NIL;
2543 DB_OBJ(tc)->range = GRN_ID_NIL;
2544 grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(tc));
2545 }
2546 GRN_API_RETURN(tc);
2547}
2548
2549grn_table_cursor *
2550grn_table_cursor_open_by_id(grn_ctx *ctx, grn_obj *table,
2551 grn_id min, grn_id max, int flags)
2552{
2553 grn_table_cursor *tc = NULL;
2554 GRN_API_ENTER;
2555 if (table) {
2556 switch (table->header.type) {
2557 case GRN_TABLE_PAT_KEY :
2558 tc = (grn_table_cursor *)grn_pat_cursor_open(ctx, (grn_pat *)table,
2559 NULL, 0, NULL, 0, 0, -1, flags);
2560 break;
2561 case GRN_TABLE_DAT_KEY :
2562 tc = (grn_table_cursor *)grn_dat_cursor_open(ctx, (grn_dat *)table,
2563 NULL, 0, NULL, 0, 0, -1, flags);
2564 break;
2565 case GRN_TABLE_HASH_KEY :
2566 tc = (grn_table_cursor *)grn_hash_cursor_open(ctx, (grn_hash *)table,
2567 NULL, 0, NULL, 0, 0, -1, flags);
2568 break;
2569 case GRN_TABLE_NO_KEY :
2570 tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
2571 min, max, 0, -1, flags);
2572 break;
2573 }
2574 }
2575 GRN_API_RETURN(tc);
2576}
2577
2578grn_rc
2579grn_table_cursor_close(grn_ctx *ctx, grn_table_cursor *tc)
2580{
2581 const char *tag = "[table][cursor][close]";
2582 grn_rc rc = GRN_SUCCESS;
2583 GRN_API_ENTER;
2584 if (!tc) {
2585 rc = GRN_INVALID_ARGUMENT;
2586 ERR(rc, "%s invalid cursor", tag);
2587 } else {
2588 {
2589 if (DB_OBJ(tc)->finalizer) {
2590 DB_OBJ(tc)->finalizer(ctx, 1, (grn_obj **)&tc, &DB_OBJ(tc)->user_data);
2591 }
2592 if (DB_OBJ(tc)->source) {
2593 GRN_FREE(DB_OBJ(tc)->source);
2594 }
2595 /*
2596 grn_hook_entry entry;
2597 for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
2598 grn_hook_free(ctx, DB_OBJ(tc)->hooks[entry]);
2599 }
2600 */
2601 grn_obj_delete_by_id(ctx, DB_OBJ(tc)->db, DB_OBJ(tc)->id, GRN_FALSE);
2602 }
2603 switch (tc->header.type) {
2604 case GRN_CURSOR_TABLE_PAT_KEY :
2605 grn_pat_cursor_close(ctx, (grn_pat_cursor *)tc);
2606 break;
2607 case GRN_CURSOR_TABLE_DAT_KEY :
2608 grn_dat_cursor_close(ctx, (grn_dat_cursor *)tc);
2609 break;
2610 case GRN_CURSOR_TABLE_HASH_KEY :
2611 grn_hash_cursor_close(ctx, (grn_hash_cursor *)tc);
2612 break;
2613 case GRN_CURSOR_TABLE_NO_KEY :
2614 grn_array_cursor_close(ctx, (grn_array_cursor *)tc);
2615 break;
2616 default :
2617 rc = GRN_INVALID_ARGUMENT;
2618 ERR(rc, "%s invalid type %d", tag, tc->header.type);
2619 break;
2620 }
2621 }
2622 GRN_API_RETURN(rc);
2623}
2624
2625inline static grn_id
2626grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc)
2627{
2628 const char *tag = "[table][cursor][next]";
2629 grn_id id = GRN_ID_NIL;
2630 if (!tc) {
2631 ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2632 } else {
2633 switch (tc->header.type) {
2634 case GRN_CURSOR_TABLE_PAT_KEY :
2635 id = grn_pat_cursor_next(ctx, (grn_pat_cursor *)tc);
2636 break;
2637 case GRN_CURSOR_TABLE_DAT_KEY :
2638 id = grn_dat_cursor_next(ctx, (grn_dat_cursor *)tc);
2639 break;
2640 case GRN_CURSOR_TABLE_HASH_KEY :
2641 id = grn_hash_cursor_next(ctx, (grn_hash_cursor *)tc);
2642 break;
2643 case GRN_CURSOR_TABLE_NO_KEY :
2644 id = grn_array_cursor_next(ctx, (grn_array_cursor *)tc);
2645 break;
2646 case GRN_CURSOR_COLUMN_INDEX :
2647 {
2648 grn_posting *ip = grn_index_cursor_next(ctx, (grn_obj *)tc, NULL);
2649 if (ip) { id = ip->rid; }
2650 }
2651 break;
2652 default :
2653 ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2654 break;
2655 }
2656 }
2657 return id;
2658}
2659
2660grn_id
2661grn_table_cursor_next(grn_ctx *ctx, grn_table_cursor *tc)
2662{
2663 grn_id id;
2664 GRN_API_ENTER;
2665 id = grn_table_cursor_next_inline(ctx, tc);
2666 GRN_API_RETURN(id);
2667}
2668
2669int
2670grn_table_cursor_get_key(grn_ctx *ctx, grn_table_cursor *tc, void **key)
2671{
2672 const char *tag = "[table][cursor][get-key]";
2673 int len = 0;
2674 GRN_API_ENTER;
2675 if (!tc) {
2676 ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2677 } else {
2678 switch (tc->header.type) {
2679 case GRN_CURSOR_TABLE_PAT_KEY :
2680 len = grn_pat_cursor_get_key(ctx, (grn_pat_cursor *)tc, key);
2681 break;
2682 case GRN_CURSOR_TABLE_DAT_KEY :
2683 len = grn_dat_cursor_get_key(ctx, (grn_dat_cursor *)tc, (const void **)key);
2684 break;
2685 case GRN_CURSOR_TABLE_HASH_KEY :
2686 len = grn_hash_cursor_get_key(ctx, (grn_hash_cursor *)tc, key);
2687 break;
2688 default :
2689 ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2690 break;
2691 }
2692 }
2693 GRN_API_RETURN(len);
2694}
2695
2696inline static int
2697grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value)
2698{
2699 const char *tag = "[table][cursor][get-value]";
2700 int len = 0;
2701 if (!tc) {
2702 ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2703 } else {
2704 switch (tc->header.type) {
2705 case GRN_CURSOR_TABLE_PAT_KEY :
2706 len = grn_pat_cursor_get_value(ctx, (grn_pat_cursor *)tc, value);
2707 break;
2708 case GRN_CURSOR_TABLE_DAT_KEY :
2709 *value = NULL;
2710 len = 0;
2711 break;
2712 case GRN_CURSOR_TABLE_HASH_KEY :
2713 len = grn_hash_cursor_get_value(ctx, (grn_hash_cursor *)tc, value);
2714 break;
2715 case GRN_CURSOR_TABLE_NO_KEY :
2716 len = grn_array_cursor_get_value(ctx, (grn_array_cursor *)tc, value);
2717 break;
2718 default :
2719 ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2720 break;
2721 }
2722 }
2723 return len;
2724}
2725
2726int
2727grn_table_cursor_get_value(grn_ctx *ctx, grn_table_cursor *tc, void **value)
2728{
2729 int len;
2730 GRN_API_ENTER;
2731 len = grn_table_cursor_get_value_inline(ctx, tc, value);
2732 GRN_API_RETURN(len);
2733}
2734
2735grn_rc
2736grn_table_cursor_set_value(grn_ctx *ctx, grn_table_cursor *tc,
2737 const void *value, int flags)
2738{
2739 const char *tag = "[table][cursor][set-value]";
2740 grn_rc rc = GRN_INVALID_ARGUMENT;
2741 GRN_API_ENTER;
2742 if (!tc) {
2743 ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2744 } else {
2745 switch (tc->header.type) {
2746 case GRN_CURSOR_TABLE_PAT_KEY :
2747 rc = grn_pat_cursor_set_value(ctx, (grn_pat_cursor *)tc, value, flags);
2748 break;
2749 case GRN_CURSOR_TABLE_DAT_KEY :
2750 rc = GRN_OPERATION_NOT_SUPPORTED;
2751 break;
2752 case GRN_CURSOR_TABLE_HASH_KEY :
2753 rc = grn_hash_cursor_set_value(ctx, (grn_hash_cursor *)tc, value, flags);
2754 break;
2755 case GRN_CURSOR_TABLE_NO_KEY :
2756 rc = grn_array_cursor_set_value(ctx, (grn_array_cursor *)tc, value, flags);
2757 break;
2758 default :
2759 ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2760 break;
2761 }
2762 }
2763 GRN_API_RETURN(rc);
2764}
2765
2766grn_rc
2767grn_table_cursor_delete(grn_ctx *ctx, grn_table_cursor *tc)
2768{
2769 const char *tag = "[table][cursor][delete]";
2770 grn_rc rc = GRN_INVALID_ARGUMENT;
2771 GRN_API_ENTER;
2772 if (!tc) {
2773 ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2774 } else {
2775 grn_id id;
2776 grn_obj *table;
2777 const void *key = NULL;
2778 unsigned int key_size = 0;
2779 switch (tc->header.type) {
2780 case GRN_CURSOR_TABLE_PAT_KEY :
2781 {
2782 grn_pat_cursor *pc = (grn_pat_cursor *)tc;
2783 id = pc->curr_rec;
2784 table = (grn_obj *)(pc->pat);
2785 key = _grn_pat_key(ctx, pc->pat, id, &key_size);
2786 rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2787 if (rc != GRN_SUCCESS) {
2788 goto exit;
2789 }
2790 rc = grn_pat_cursor_delete(ctx, pc, NULL);
2791 }
2792 break;
2793 case GRN_CURSOR_TABLE_DAT_KEY :
2794 rc = GRN_OPERATION_NOT_SUPPORTED;
2795 break;
2796 case GRN_CURSOR_TABLE_HASH_KEY :
2797 {
2798 grn_hash_cursor *hc = (grn_hash_cursor *)tc;
2799 id = hc->curr_rec;
2800 table = (grn_obj *)(hc->hash);
2801 key = _grn_hash_key(ctx, hc->hash, id, &key_size);
2802 rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2803 if (rc != GRN_SUCCESS) {
2804 goto exit;
2805 }
2806 rc = grn_hash_cursor_delete(ctx, hc, NULL);
2807 }
2808 break;
2809 case GRN_CURSOR_TABLE_NO_KEY :
2810 {
2811 grn_array_cursor *ac = (grn_array_cursor *)tc;
2812 id = ac->curr_rec;
2813 table = (grn_obj *)(ac->array);
2814 rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
2815 if (rc != GRN_SUCCESS) {
2816 goto exit;
2817 }
2818 rc = grn_array_cursor_delete(ctx, ac, NULL);
2819 }
2820 break;
2821 default :
2822 ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2823 break;
2824 }
2825 }
2826exit :
2827 GRN_API_RETURN(rc);
2828}
2829
2830grn_obj *
2831grn_table_cursor_table(grn_ctx *ctx, grn_table_cursor *tc)
2832{
2833 const char *tag = "[table][cursor][table]";
2834 grn_obj *obj = NULL;
2835 GRN_API_ENTER;
2836 if (!tc) {
2837 ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
2838 } else {
2839 switch (tc->header.type) {
2840 case GRN_CURSOR_TABLE_PAT_KEY :
2841 obj = (grn_obj *)(((grn_pat_cursor *)tc)->pat);
2842 break;
2843 case GRN_CURSOR_TABLE_DAT_KEY :
2844 obj = (grn_obj *)(((grn_dat_cursor *)tc)->dat);
2845 break;
2846 case GRN_CURSOR_TABLE_HASH_KEY :
2847 obj = (grn_obj *)(((grn_hash_cursor *)tc)->hash);
2848 break;
2849 case GRN_CURSOR_TABLE_NO_KEY :
2850 obj = (grn_obj *)(((grn_array_cursor *)tc)->array);
2851 break;
2852 default :
2853 ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
2854 break;
2855 }
2856 }
2857 GRN_API_RETURN(obj);
2858}
2859
2860typedef struct {
2861 grn_db_obj obj;
2862 grn_obj *index;
2863 grn_table_cursor *tc;
2864 grn_ii_cursor *iic;
2865 grn_id tid;
2866 grn_id rid_min;
2867 grn_id rid_max;
2868 int flags;
2869} grn_index_cursor;
2870
2871grn_obj *
2872grn_index_cursor_open(grn_ctx *ctx, grn_table_cursor *tc,
2873 grn_obj *index, grn_id rid_min, grn_id rid_max, int flags)
2874{
2875 grn_index_cursor *ic = NULL;
2876 GRN_API_ENTER;
2877 if (tc && (ic = GRN_MALLOCN(grn_index_cursor, 1))) {
2878 ic->tc = tc;
2879 ic->index = index;
2880 ic->iic = NULL;
2881 ic->tid = GRN_ID_NIL;
2882 ic->rid_min = rid_min;
2883 ic->rid_max = rid_max;
2884 ic->flags = flags;
2885 GRN_DB_OBJ_SET_TYPE(ic, GRN_CURSOR_COLUMN_INDEX);
2886 {
2887 grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
2888 DB_OBJ(ic)->header.domain = GRN_ID_NIL;
2889 DB_OBJ(ic)->range = GRN_ID_NIL;
2890 grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(ic));
2891 }
2892 }
2893 GRN_API_RETURN((grn_obj *)ic);
2894}
2895
2896grn_posting *
2897grn_index_cursor_next(grn_ctx *ctx, grn_obj *c, grn_id *tid)
2898{
2899 grn_posting *ip = NULL;
2900 grn_index_cursor *ic = (grn_index_cursor *)c;
2901 GRN_API_ENTER;
2902 if (ic->iic) {
2903 if (ic->flags & GRN_OBJ_WITH_POSITION) {
2904 ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2905 while (!ip && grn_ii_cursor_next(ctx, ic->iic)) {
2906 ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2907 break;
2908 }
2909 } else {
2910 ip = grn_ii_cursor_next(ctx, ic->iic);
2911 }
2912 }
2913 if (!ip) {
2914 while ((ic->tid = grn_table_cursor_next_inline(ctx, ic->tc))) {
2915 grn_ii *ii = (grn_ii *)ic->index;
2916 if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
2917 if ((ic->iic = grn_ii_cursor_open(ctx, ii, ic->tid,
2918 ic->rid_min, ic->rid_max,
2919 ii->n_elements, ic->flags))) {
2920 ip = grn_ii_cursor_next(ctx, ic->iic);
2921 if (ip && ic->flags & GRN_OBJ_WITH_POSITION) {
2922 ip = grn_ii_cursor_next_pos(ctx, ic->iic);
2923 }
2924 if (ip) {
2925 break;
2926 }
2927 }
2928 }
2929 }
2930 if (tid) { *tid = ic->tid; }
2931 GRN_API_RETURN((grn_posting *)ip);
2932}
2933
2934grn_rc
2935grn_table_search(grn_ctx *ctx, grn_obj *table, const void *key, uint32_t key_size,
2936 grn_operator mode, grn_obj *res, grn_operator op)
2937{
2938 grn_rc rc = GRN_SUCCESS;
2939 GRN_API_ENTER;
2940 switch (table->header.type) {
2941 case GRN_TABLE_PAT_KEY :
2942 {
2943 grn_pat *pat = (grn_pat *)table;
2944 WITH_NORMALIZE(pat, key, key_size, {
2945 switch (mode) {
2946 case GRN_OP_EXACT :
2947 {
2948 grn_id id = grn_pat_get(ctx, pat, key, key_size, NULL);
2949 if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2950 }
2951 // todo : support op;
2952 break;
2953 case GRN_OP_LCP :
2954 {
2955 grn_id id = grn_pat_lcp_search(ctx, pat, key, key_size);
2956 if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
2957 }
2958 // todo : support op;
2959 break;
2960 case GRN_OP_SUFFIX :
2961 rc = grn_pat_suffix_search(ctx, pat, key, key_size, (grn_hash *)res);
2962 // todo : support op;
2963 break;
2964 case GRN_OP_PREFIX :
2965 rc = grn_pat_prefix_search(ctx, pat, key, key_size, (grn_hash *)res);
2966 // todo : support op;
2967 break;
2968 case GRN_OP_TERM_EXTRACT :
2969 {
2970 int len;
2971 grn_id tid;
2972 const char *sp = key;
2973 const char *se = sp + key_size;
2974 for (; sp < se; sp += len) {
2975 if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
2976 grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
2977 /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
2978 }
2979 if (!(len = grn_charlen(ctx, sp, se))) { break; }
2980 }
2981 }
2982 // todo : support op;
2983 break;
2984 default :
2985 rc = GRN_INVALID_ARGUMENT;
2986 ERR(rc, "invalid mode %d", mode);
2987 }
2988 });
2989 }
2990 break;
2991 case GRN_TABLE_DAT_KEY :
2992 {
2993 grn_dat *dat = (grn_dat *)table;
2994 WITH_NORMALIZE(dat, key, key_size, {
2995 switch (mode) {
2996 case GRN_OP_EXACT :
2997 {
2998 grn_id id = grn_dat_get(ctx, dat, key, key_size, NULL);
2999 if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
3000 }
3001 break;
3002 case GRN_OP_PREFIX :
3003 {
3004 grn_dat_cursor *dc = grn_dat_cursor_open(ctx, dat, key, key_size, NULL, 0,
3005 0, -1, GRN_CURSOR_PREFIX);
3006 if (dc) {
3007 grn_id id;
3008 while ((id = grn_dat_cursor_next(ctx, dc))) {
3009 grn_table_add(ctx, res, &id, sizeof(grn_id), NULL);
3010 }
3011 grn_dat_cursor_close(ctx, dc);
3012 }
3013 }
3014 break;
3015 case GRN_OP_LCP :
3016 {
3017 grn_id id = grn_dat_lcp_search(ctx, dat, key, key_size);
3018 if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
3019 }
3020 break;
3021 case GRN_OP_TERM_EXTRACT :
3022 {
3023 int len;
3024 grn_id tid;
3025 const char *sp = key;
3026 const char *se = sp + key_size;
3027 for (; sp < se; sp += len) {
3028 if ((tid = grn_dat_lcp_search(ctx, dat, sp, se - sp))) {
3029 grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
3030 /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
3031 }
3032 if (!(len = grn_charlen(ctx, sp, se))) { break; }
3033 }
3034 }
3035 // todo : support op;
3036 break;
3037 default :
3038 rc = GRN_INVALID_ARGUMENT;
3039 ERR(rc, "invalid mode %d", mode);
3040 }
3041 });
3042 }
3043 break;
3044 case GRN_TABLE_HASH_KEY :
3045 {
3046 grn_hash *hash = (grn_hash *)table;
3047 grn_id id = GRN_ID_NIL;
3048 WITH_NORMALIZE(hash, key, key_size, {
3049 id = grn_hash_get(ctx, hash, key, key_size, NULL);
3050 });
3051 if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
3052 }
3053 break;
3054 }
3055 GRN_API_RETURN(rc);
3056}
3057
3058grn_rc
3059grn_table_fuzzy_search(grn_ctx *ctx, grn_obj *table, const void *key, uint32_t key_size,
3060 grn_fuzzy_search_optarg *args, grn_obj *res, grn_operator op)
3061{
3062 grn_rc rc = GRN_SUCCESS;
3063 GRN_API_ENTER;
3064 switch (table->header.type) {
3065 case GRN_TABLE_PAT_KEY :
3066 {
3067 grn_pat *pat = (grn_pat *)table;
3068 if (!grn_table_size(ctx, res) && op == GRN_OP_OR) {
3069 WITH_NORMALIZE(pat, key, key_size, {
3070 rc = grn_pat_fuzzy_search(ctx, pat, key, key_size,
3071 args, (grn_hash *)res);
3072 });
3073 } else {
3074 grn_obj *hash;
3075 hash = grn_table_create(ctx, NULL, 0, NULL,
3076 GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3077 table, NULL);
3078 WITH_NORMALIZE(pat, key, key_size, {
3079 rc = grn_pat_fuzzy_search(ctx, pat, key, key_size,
3080 args, (grn_hash *)hash);
3081 });
3082 if (rc == GRN_SUCCESS) {
3083 rc = grn_table_setoperation(ctx, res, hash, res, op);
3084 }
3085 grn_obj_unlink(ctx, hash);
3086 }
3087 }
3088 break;
3089 default :
3090 rc = GRN_OPERATION_NOT_SUPPORTED;
3091 break;
3092 }
3093 GRN_API_RETURN(rc);
3094}
3095
3096grn_id
3097grn_table_next(grn_ctx *ctx, grn_obj *table, grn_id id)
3098{
3099 grn_id r = GRN_ID_NIL;
3100 GRN_API_ENTER;
3101 if (table) {
3102 switch (table->header.type) {
3103 case GRN_TABLE_PAT_KEY :
3104 r = grn_pat_next(ctx, (grn_pat *)table, id);
3105 break;
3106 case GRN_TABLE_DAT_KEY :
3107 r = grn_dat_next(ctx, (grn_dat *)table, id);
3108 break;
3109 case GRN_TABLE_HASH_KEY :
3110 r = grn_hash_next(ctx, (grn_hash *)table, id);
3111 break;
3112 case GRN_TABLE_NO_KEY :
3113 r = grn_array_next(ctx, (grn_array *)table, id);
3114 break;
3115 }
3116 }
3117 GRN_API_RETURN(r);
3118}
3119
3120static grn_rc
3121grn_accessor_resolve_one_index_column(grn_ctx *ctx, grn_accessor *accessor,
3122 grn_obj *current_res, grn_obj **next_res)
3123{
3124 grn_rc rc = GRN_SUCCESS;
3125 grn_obj *column = NULL;
3126 grn_id next_res_domain_id = GRN_ID_NIL;
3127
3128 {
3129 grn_obj *index;
3130 grn_obj source_ids;
3131 unsigned int i, n_ids;
3132
3133 index = accessor->obj;
3134 next_res_domain_id = index->header.domain;
3135
3136 GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
3137 grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
3138 n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
3139 for (i = 0; i < n_ids; i++) {
3140 grn_id source_id;
3141 grn_obj *source;
3142
3143 source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
3144 source = grn_ctx_at(ctx, source_id);
3145 if (DB_OBJ(source)->range == next_res_domain_id) {
3146 column = source;
3147 break;
3148 }
3149 grn_obj_unlink(ctx, source);
3150 }
3151
3152 if (!column) {
3153 return GRN_INVALID_ARGUMENT;
3154 }
3155 }
3156
3157 {
3158 grn_rc rc;
3159 grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
3160 *next_res = grn_table_create(ctx, NULL, 0, NULL,
3161 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3162 next_res_domain, NULL);
3163 rc = ctx->rc;
3164 grn_obj_unlink(ctx, next_res_domain);
3165 if (!*next_res) {
3166 return rc;
3167 }
3168 }
3169
3170 {
3171 grn_obj_flags column_value_flags = 0;
3172 grn_obj column_value;
3173 grn_posting add_posting;
3174 grn_id *tid;
3175 grn_rset_recinfo *recinfo;
3176
3177 if (column->header.type == GRN_COLUMN_VAR_SIZE) {
3178 column_value_flags |= GRN_OBJ_VECTOR;
3179 }
3180 GRN_VALUE_FIX_SIZE_INIT(&column_value,
3181 column_value_flags,
3182 next_res_domain_id);
3183
3184 add_posting.sid = 0;
3185 add_posting.pos = 0;
3186 add_posting.weight = 0;
3187
3188 GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &tid, NULL, &recinfo, {
3189 int i;
3190 int n_elements;
3191
3192 add_posting.weight = recinfo->score - 1;
3193
3194 GRN_BULK_REWIND(&column_value);
3195 grn_obj_get_value(ctx, column, *tid, &column_value);
3196
3197 n_elements = GRN_BULK_VSIZE(&column_value) / sizeof(grn_id);
3198 for (i = 0; i < n_elements; i++) {
3199 add_posting.rid = GRN_RECORD_VALUE_AT(&column_value, i);
3200 rc = grn_ii_posting_add(ctx,
3201 &add_posting,
3202 (grn_hash *)*next_res,
3203 GRN_OP_OR);
3204 if (rc != GRN_SUCCESS) {
3205 break;
3206 }
3207 }
3208 if (rc != GRN_SUCCESS) {
3209 break;
3210 }
3211 });
3212
3213 GRN_OBJ_FIN(ctx, &column_value);
3214 }
3215
3216 if (rc != GRN_SUCCESS) {
3217 grn_obj_unlink(ctx, *next_res);
3218 }
3219
3220 return rc;
3221}
3222
3223static grn_rc
3224grn_accessor_resolve_one_table(grn_ctx *ctx, grn_accessor *accessor,
3225 grn_obj *current_res, grn_obj **next_res)
3226{
3227 grn_rc rc = GRN_SUCCESS;
3228 grn_obj *table;
3229
3230 table = accessor->obj;
3231 *next_res = grn_table_create(ctx, NULL, 0, NULL,
3232 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3233 table, NULL);
3234 if (!*next_res) {
3235 return ctx->rc;
3236 }
3237
3238 grn_report_table(ctx,
3239 "[accessor][resolve]",
3240 "",
3241 table);
3242
3243 {
3244 grn_posting posting;
3245
3246 memset(&posting, 0, sizeof(posting));
3247 GRN_HASH_EACH_BEGIN(ctx, (grn_hash *)current_res, cursor, id) {
3248 void *key;
3249 void *value;
3250 grn_id *record_id;
3251 grn_rset_recinfo *recinfo;
3252 grn_id next_record_id;
3253
3254 grn_hash_cursor_get_key_value(ctx, cursor, &key, NULL, &value);
3255 record_id = key;
3256 recinfo = value;
3257 next_record_id = grn_table_get(ctx,
3258 table,
3259 record_id,
3260 sizeof(grn_id));
3261 if (next_record_id == GRN_ID_NIL) {
3262 continue;
3263 }
3264
3265 posting.rid = next_record_id;
3266 posting.weight = recinfo->score;
3267 rc = grn_ii_posting_add(ctx,
3268 &posting,
3269 (grn_hash *)*next_res,
3270 GRN_OP_OR);
3271 if (rc != GRN_SUCCESS) {
3272 break;
3273 }
3274 } GRN_HASH_EACH_END(ctx, cursor);
3275 }
3276
3277 if (rc != GRN_SUCCESS) {
3278 grn_obj_unlink(ctx, *next_res);
3279 }
3280
3281 return rc;
3282}
3283
3284static grn_rc
3285grn_accessor_resolve_one_data_column(grn_ctx *ctx, grn_accessor *accessor,
3286 grn_obj *current_res, grn_obj **next_res)
3287{
3288 grn_rc rc = GRN_SUCCESS;
3289 grn_index_datum index_datum;
3290 unsigned int n_index_data;
3291 grn_id next_res_domain_id = GRN_ID_NIL;
3292
3293 n_index_data = grn_column_get_all_index_data(ctx,
3294 accessor->obj,
3295 &index_datum,
3296 1);
3297 if (n_index_data == 0) {
3298 return GRN_INVALID_ARGUMENT;
3299 }
3300
3301 {
3302 grn_obj *lexicon;
3303 lexicon = grn_ctx_at(ctx, index_datum.index->header.domain);
3304 if (grn_obj_id(ctx, lexicon) != current_res->header.domain) {
3305 char index_name[GRN_TABLE_MAX_KEY_SIZE];
3306 int index_name_size;
3307 grn_obj *expected;
3308 char expected_name[GRN_TABLE_MAX_KEY_SIZE];
3309 int expected_name_size;
3310
3311 index_name_size = grn_obj_name(ctx,
3312 index_datum.index,
3313 index_name,
3314 GRN_TABLE_MAX_KEY_SIZE);
3315 expected = grn_ctx_at(ctx, current_res->header.domain);
3316 expected_name_size = grn_obj_name(ctx,
3317 expected,
3318 expected_name,
3319 GRN_TABLE_MAX_KEY_SIZE);
3320 ERR(GRN_INVALID_ARGUMENT,
3321 "[accessor][resolve][data-column] lexicon mismatch index: "
3322 "<%.*s> "
3323 "expected:<%.*s>",
3324 index_name_size,
3325 index_name,
3326 expected_name_size,
3327 expected_name);
3328 return ctx->rc;
3329 }
3330 }
3331
3332 next_res_domain_id = DB_OBJ(index_datum.index)->range;
3333
3334 grn_report_index(ctx,
3335 "[accessor][resolve][data-column]",
3336 "",
3337 index_datum.index);
3338 {
3339 grn_rc rc;
3340 grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
3341 *next_res = grn_table_create(ctx, NULL, 0, NULL,
3342 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3343 next_res_domain, NULL);
3344 rc = ctx->rc;
3345 grn_obj_unlink(ctx, next_res_domain);
3346 if (!*next_res) {
3347 return rc;
3348 }
3349 }
3350
3351 {
3352 grn_id *tid;
3353 grn_rset_recinfo *recinfo;
3354
3355 GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &tid, NULL, &recinfo, {
3356 grn_ii *ii = (grn_ii *)(index_datum.index);
3357 grn_ii_cursor *ii_cursor;
3358 grn_posting *posting;
3359
3360 ii_cursor = grn_ii_cursor_open(ctx, ii, *tid,
3361 GRN_ID_NIL, GRN_ID_MAX,
3362 ii->n_elements,
3363 0);
3364 if (!ii_cursor) {
3365 continue;
3366 }
3367
3368 while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
3369 grn_posting add_posting;
3370
3371 if (index_datum.section > 0 && posting->sid != index_datum.section) {
3372 continue;
3373 }
3374
3375 add_posting = *posting;
3376 add_posting.weight += recinfo->score - 1;
3377 rc = grn_ii_posting_add(ctx,
3378 &add_posting,
3379 (grn_hash *)*next_res,
3380 GRN_OP_OR);
3381 if (rc != GRN_SUCCESS) {
3382 break;
3383 }
3384 }
3385 grn_ii_cursor_close(ctx, ii_cursor);
3386
3387 if (rc != GRN_SUCCESS) {
3388 break;
3389 }
3390 });
3391 }
3392
3393 if (rc != GRN_SUCCESS) {
3394 grn_obj_unlink(ctx, *next_res);
3395 }
3396
3397 return rc;
3398}
3399
3400grn_rc
3401grn_accessor_resolve(grn_ctx *ctx, grn_obj *accessor, int deep,
3402 grn_obj *base_res, grn_obj *res,
3403 grn_operator op)
3404{
3405 grn_rc rc = GRN_SUCCESS;
3406 grn_accessor *a;
3407 grn_obj accessor_stack;
3408 int i, n_accessors;
3409 grn_obj *current_res = base_res;
3410
3411 GRN_PTR_INIT(&accessor_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
3412 n_accessors = 0;
3413 for (a = (grn_accessor *)accessor; a; a = a->next) {
3414 if (deep == n_accessors) {
3415 break;
3416 }
3417 GRN_PTR_PUT(ctx, &accessor_stack, a);
3418 n_accessors++;
3419 }
3420
3421 for (i = n_accessors; i > 0; i--) {
3422 grn_obj *next_res = NULL;
3423
3424 a = (grn_accessor *)GRN_PTR_VALUE_AT(&accessor_stack, i - 1);
3425 if (a->obj->header.type == GRN_COLUMN_INDEX) {
3426 rc = grn_accessor_resolve_one_index_column(ctx, a,
3427 current_res, &next_res);
3428 } else if (grn_obj_is_table(ctx, a->obj)) {
3429 rc = grn_accessor_resolve_one_table(ctx, a,
3430 current_res, &next_res);
3431 } else {
3432 rc = grn_accessor_resolve_one_data_column(ctx, a,
3433 current_res, &next_res);
3434 }
3435
3436 if (current_res != base_res) {
3437 grn_obj_unlink(ctx, current_res);
3438 }
3439
3440 if (rc != GRN_SUCCESS) {
3441 break;
3442 }
3443
3444 current_res = next_res;
3445 }
3446
3447 if (rc == GRN_SUCCESS && current_res != base_res) {
3448 grn_id *record_id;
3449 grn_rset_recinfo *recinfo;
3450 GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &record_id, NULL, &recinfo, {
3451 grn_posting posting;
3452 posting.rid = *record_id;
3453 posting.sid = 1;
3454 posting.pos = 0;
3455 posting.weight = recinfo->score - 1;
3456 grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
3457 });
3458 grn_obj_unlink(ctx, current_res);
3459 grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
3460 } else {
3461 if (rc == GRN_SUCCESS) {
3462 rc = GRN_INVALID_ARGUMENT;
3463 }
3464 }
3465
3466 GRN_OBJ_FIN(ctx, &accessor_stack);
3467 return rc;
3468}
3469
3470static inline void
3471grn_obj_search_index_report(grn_ctx *ctx, const char *tag, grn_obj *index)
3472{
3473 grn_report_index(ctx, "[object][search]", tag, index);
3474}
3475
3476static inline grn_rc
3477grn_obj_search_accessor(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
3478 grn_obj *res, grn_operator op, grn_search_optarg *optarg)
3479{
3480 grn_rc rc = GRN_SUCCESS;
3481 grn_accessor *a;
3482 grn_obj *last_obj = NULL;
3483 int n_accessors;
3484
3485 for (a = (grn_accessor *)obj; a; a = a->next) {
3486 if (!a->next) {
3487 last_obj = a->obj;
3488 }
3489 }
3490 n_accessors = 0;
3491 for (a = (grn_accessor *)obj; a; a = a->next) {
3492 n_accessors++;
3493 if (GRN_OBJ_INDEX_COLUMNP(a->obj)) {
3494 break;
3495 }
3496 }
3497
3498 {
3499 grn_obj *index;
3500 grn_operator index_op = GRN_OP_MATCH;
3501 if (optarg && optarg->mode != GRN_OP_EXACT) {
3502 index_op = optarg->mode;
3503 }
3504 if (grn_column_index(ctx, last_obj, index_op, &index, 1, NULL) == 0) {
3505 rc = GRN_INVALID_ARGUMENT;
3506 goto exit;
3507 }
3508
3509 if (n_accessors == 1) {
3510 rc = grn_obj_search(ctx, index, query, res, op, optarg);
3511 } else {
3512 grn_obj *base_res;
3513 grn_obj *range = grn_ctx_at(ctx, DB_OBJ(index)->range);
3514 base_res = grn_table_create(ctx, NULL, 0, NULL,
3515 GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
3516 range,
3517 NULL);
3518 rc = ctx->rc;
3519 grn_obj_unlink(ctx, range);
3520 if (!base_res) {
3521 goto exit;
3522 }
3523 if (optarg) {
3524 optarg->match_info.min = GRN_ID_NIL;
3525 }
3526 rc = grn_obj_search(ctx, index, query, base_res, GRN_OP_OR, optarg);
3527 if (rc != GRN_SUCCESS) {
3528 grn_obj_unlink(ctx, base_res);
3529 goto exit;
3530 }
3531 rc = grn_accessor_resolve(ctx, obj, n_accessors - 1, base_res, res, op);
3532 grn_obj_unlink(ctx, base_res);
3533 }
3534 }
3535
3536exit :
3537 return rc;
3538}
3539
3540static grn_rc
3541grn_obj_search_column_index_by_id(grn_ctx *ctx, grn_obj *obj,
3542 grn_id tid,
3543 grn_obj *res, grn_operator op,
3544 grn_search_optarg *optarg)
3545{
3546 grn_ii_cursor *c;
3547
3548 grn_obj_search_index_report(ctx, "[id]", obj);
3549
3550 c = grn_ii_cursor_open(ctx, (grn_ii *)obj, tid,
3551 GRN_ID_NIL, GRN_ID_MAX, 1, 0);
3552 if (c) {
3553 grn_posting *pos;
3554 grn_hash *s = (grn_hash *)res;
3555 while ((pos = grn_ii_cursor_next(ctx, c))) {
3556 /* todo: support orgarg(op)
3557 res_add(ctx, s, (grn_rset_posinfo *) pos,
3558 get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg), op);
3559 */
3560 grn_hash_add(ctx, s, pos, s->key_size, NULL, NULL);
3561 }
3562 grn_ii_cursor_close(ctx, c);
3563 }
3564
3565 return GRN_SUCCESS;
3566}
3567
3568static grn_rc
3569grn_obj_search_column_index_by_key(grn_ctx *ctx, grn_obj *obj,
3570 grn_obj *query,
3571 grn_obj *res, grn_operator op,
3572 grn_search_optarg *optarg)
3573{
3574 grn_rc rc;
3575 unsigned int key_type = GRN_ID_NIL;
3576 const char *key;
3577 unsigned int key_len;
3578 grn_obj *table;
3579 grn_obj casted_query;
3580 grn_bool need_cast = GRN_FALSE;
3581
3582 table = grn_ctx_at(ctx, obj->header.domain);
3583 if (table) {
3584 key_type = table->header.domain;
3585 need_cast = (query->header.domain != key_type);
3586 grn_obj_unlink(ctx, table);
3587 }
3588 if (need_cast) {
3589 GRN_OBJ_INIT(&casted_query, GRN_BULK, 0, key_type);
3590 rc = grn_obj_cast(ctx, query, &casted_query, GRN_FALSE);
3591 if (rc == GRN_SUCCESS) {
3592 key = GRN_BULK_HEAD(&casted_query);
3593 key_len = GRN_BULK_VSIZE(&casted_query);
3594 }
3595 } else {
3596 rc = GRN_SUCCESS;
3597 key = GRN_BULK_HEAD(query);
3598 key_len = GRN_BULK_VSIZE(query);
3599 }
3600 if (rc == GRN_SUCCESS) {
3601 if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
3602 const char *tag;
3603 if (optarg) {
3604 switch (optarg->mode) {
3605 case GRN_OP_MATCH :
3606 tag = "[key][match]";
3607 break;
3608 case GRN_OP_EXACT :
3609 tag = "[key][exact]";
3610 break;
3611 case GRN_OP_NEAR :
3612 tag = "[key][near]";
3613 break;
3614 case GRN_OP_NEAR2 :
3615 tag = "[key][near2]";
3616 break;
3617 case GRN_OP_SIMILAR :
3618 tag = "[key][similar]";
3619 break;
3620 case GRN_OP_REGEXP :
3621 tag = "[key][regexp]";
3622 break;
3623 case GRN_OP_FUZZY :
3624 tag = "[key][fuzzy]";
3625 break;
3626 default :
3627 tag = "[key][unknown]";
3628 break;
3629 }
3630 } else {
3631 tag = "[key][exact]";
3632 }
3633 grn_obj_search_index_report(ctx, tag, obj);
3634 }
3635 rc = grn_ii_sel(ctx, (grn_ii *)obj, key, key_len,
3636 (grn_hash *)res, op, optarg);
3637 }
3638 if (need_cast) {
3639 GRN_OBJ_FIN(ctx, &casted_query);
3640 }
3641
3642 return rc;
3643}
3644
3645static grn_rc
3646grn_obj_search_column_index(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
3647 grn_obj *res, grn_operator op,
3648 grn_search_optarg *optarg)
3649{
3650 grn_rc rc = GRN_INVALID_ARGUMENT;
3651
3652 if (DB_OBJ(obj)->range == res->header.domain) {
3653 switch (query->header.type) {
3654 case GRN_BULK :
3655 if (query->header.domain == obj->header.domain &&
3656 GRN_BULK_VSIZE(query) == sizeof(grn_id)) {
3657 grn_id tid = GRN_RECORD_VALUE(query);
3658 rc = grn_obj_search_column_index_by_id(ctx, obj, tid, res, op, optarg);
3659 } else {
3660 rc = grn_obj_search_column_index_by_key(ctx, obj, query,
3661 res, op, optarg);
3662 }
3663 break;
3664 case GRN_QUERY :
3665 rc = GRN_FUNCTION_NOT_IMPLEMENTED;
3666 break;
3667 }
3668 }
3669
3670 return rc;
3671}
3672
3673grn_rc
3674grn_obj_search(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
3675 grn_obj *res, grn_operator op, grn_search_optarg *optarg)
3676{
3677 grn_rc rc = GRN_INVALID_ARGUMENT;
3678 GRN_API_ENTER;
3679 if (GRN_ACCESSORP(obj)) {
3680 rc = grn_obj_search_accessor(ctx, obj, query, res, op, optarg);
3681 } else if (GRN_DB_OBJP(obj)) {
3682 switch (obj->header.type) {
3683 case GRN_TABLE_PAT_KEY :
3684 case GRN_TABLE_DAT_KEY :
3685 case GRN_TABLE_HASH_KEY :
3686 {
3687 const void *key = GRN_BULK_HEAD(query);
3688 uint32_t key_size = GRN_BULK_VSIZE(query);
3689 grn_operator mode = optarg ? optarg->mode : GRN_OP_EXACT;
3690 if (key && key_size) {
3691 if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
3692 const char *tag;
3693 if (optarg) {
3694 switch (optarg->mode) {
3695 case GRN_OP_EXACT :
3696 tag = "[table][exact]";
3697 break;
3698 case GRN_OP_LCP :
3699 tag = "[table][lcp]";
3700 break;
3701 case GRN_OP_SUFFIX :
3702 tag = "[table][suffix]";
3703 break;
3704 case GRN_OP_PREFIX :
3705 tag = "[table][prefix]";
3706 break;
3707 case GRN_OP_TERM_EXTRACT :
3708 tag = "[table][term-extract]";
3709 break;
3710 case GRN_OP_FUZZY :
3711 tag = "[table][fuzzy]";
3712 break;
3713 default :
3714 tag = "[table][unknown]";
3715 break;
3716 }
3717 } else {
3718 tag = "[table][exact]";
3719 }
3720 grn_obj_search_index_report(ctx, tag, obj);
3721 }
3722 if (optarg && optarg->mode == GRN_OP_FUZZY) {
3723 rc = grn_table_fuzzy_search(ctx, obj, key, key_size,
3724 &(optarg->fuzzy), res, op);
3725 } else {
3726 rc = grn_table_search(ctx, obj, key, key_size, mode, res, op);
3727 }
3728 }
3729 }
3730 break;
3731 case GRN_COLUMN_INDEX :
3732 rc = grn_obj_search_column_index(ctx, obj, query, res, op, optarg);
3733 break;
3734 }
3735 }
3736 GRN_API_RETURN(rc);
3737}
3738
3739#define GRN_TABLE_GROUP_BY_KEY 0
3740#define GRN_TABLE_GROUP_BY_VALUE 1
3741#define GRN_TABLE_GROUP_BY_COLUMN_VALUE 2
3742
3743#define GRN_TABLE_GROUP_FILTER_PREFIX 0
3744#define GRN_TABLE_GROUP_FILTER_SUFFIX (1L<<2)
3745
3746inline static void
3747grn_table_group_add_subrec(grn_ctx *ctx,
3748 grn_obj *table,
3749 grn_rset_recinfo *ri, double score,
3750 grn_rset_posinfo *pi, int dir,
3751 grn_obj *calc_target,
3752 grn_obj *value_buffer)
3753{
3754 grn_table_group_flags flags;
3755
3756 if (!(DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC)) {
3757 return;
3758 }
3759
3760 grn_table_add_subrec_inline(table, ri, score, pi, dir);
3761
3762 flags = DB_OBJ(table)->flags.group;
3763
3764 if (!(flags & (GRN_TABLE_GROUP_CALC_MAX |
3765 GRN_TABLE_GROUP_CALC_MIN |
3766 GRN_TABLE_GROUP_CALC_SUM |
3767 GRN_TABLE_GROUP_CALC_AVG))) {
3768 return;
3769 }
3770
3771 GRN_BULK_REWIND(value_buffer);
3772 grn_obj_get_value(ctx, calc_target, pi->rid, value_buffer);
3773 grn_rset_recinfo_update_calc_values(ctx, ri, table, value_buffer);
3774}
3775
3776static grn_bool
3777accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key,
3778 grn_table_group_result *result)
3779{
3780 grn_obj *res = result->table;
3781 grn_obj *calc_target = result->calc_target;
3782 if (key->header.type == GRN_ACCESSOR) {
3783 grn_accessor *a = (grn_accessor *)key;
3784 if (a->action == GRN_ACCESSOR_GET_KEY &&
3785 a->next && a->next->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
3786 a->next->obj && !a->next->next) {
3787 grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
3788 int idp = GRN_OBJ_TABLEP(range);
3789 grn_table_cursor *tc;
3790 if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3791 grn_bool processed = GRN_TRUE;
3792 grn_obj value_buffer;
3793 GRN_VOID_INIT(&value_buffer);
3794 switch (a->next->obj->header.type) {
3795 case GRN_COLUMN_FIX_SIZE :
3796 {
3797 grn_id id;
3798 grn_ra *ra = (grn_ra *)a->next->obj;
3799 unsigned int element_size = (ra)->header->element_size;
3800 grn_ra_cache cache;
3801 GRN_RA_CACHE_INIT(ra, &cache);
3802 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3803 void *v, *value;
3804 grn_id *id_;
3805 uint32_t key_size;
3806 grn_rset_recinfo *ri = NULL;
3807 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3808 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3809 }
3810 id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
3811 v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
3812 if (idp && *((grn_id *)v) &&
3813 grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
3814 continue;
3815 }
3816 if ((!idp || *((grn_id *)v)) &&
3817 grn_table_add_v_inline(ctx, res, v, element_size, &value, NULL)) {
3818 grn_table_group_add_subrec(ctx, res, value,
3819 ri ? ri->score : 0,
3820 (grn_rset_posinfo *)&id, 0,
3821 calc_target,
3822 &value_buffer);
3823 }
3824 }
3825 GRN_RA_CACHE_FIN(ra, &cache);
3826 }
3827 break;
3828 case GRN_COLUMN_VAR_SIZE :
3829 if (idp) { /* todo : support other type */
3830 grn_id id;
3831 grn_ja *ja = (grn_ja *)a->next->obj;
3832 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3833 grn_io_win jw;
3834 unsigned int len = 0;
3835 void *value;
3836 grn_id *v, *id_;
3837 uint32_t key_size;
3838 grn_rset_recinfo *ri = NULL;
3839 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3840 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3841 }
3842 id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
3843 if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
3844 while (len) {
3845 if ((*v != GRN_ID_NIL) &&
3846 grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
3847 grn_table_group_add_subrec(ctx, res, value,
3848 ri ? ri->score : 0,
3849 (grn_rset_posinfo *)&id, 0,
3850 calc_target,
3851 &value_buffer);
3852 }
3853 v++;
3854 len -= sizeof(grn_id);
3855 }
3856 grn_ja_unref(ctx, &jw);
3857 }
3858 }
3859 } else {
3860 processed = GRN_FALSE;
3861 }
3862 break;
3863 default :
3864 processed = GRN_FALSE;
3865 break;
3866 }
3867 GRN_OBJ_FIN(ctx, &value_buffer);
3868 grn_table_cursor_close(ctx, tc);
3869 return processed;
3870 }
3871 }
3872 }
3873 return GRN_FALSE;
3874}
3875
3876static void
3877grn_table_group_single_key_records(grn_ctx *ctx, grn_obj *table,
3878 grn_obj *key, grn_table_group_result *result)
3879{
3880 grn_obj bulk;
3881 grn_obj value_buffer;
3882 grn_table_cursor *tc;
3883 grn_obj *res = result->table;
3884 grn_obj *calc_target = result->calc_target;
3885
3886 GRN_TEXT_INIT(&bulk, 0);
3887 GRN_VOID_INIT(&value_buffer);
3888 if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3889 grn_id id;
3890 grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
3891 int idp = GRN_OBJ_TABLEP(range);
3892 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
3893 void *value;
3894 grn_rset_recinfo *ri = NULL;
3895 GRN_BULK_REWIND(&bulk);
3896 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
3897 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
3898 }
3899 grn_obj_get_value(ctx, key, id, &bulk);
3900 switch (bulk.header.type) {
3901 case GRN_UVECTOR :
3902 {
3903 grn_bool is_reference;
3904 unsigned int element_size;
3905 uint8_t *elements;
3906 int i, n_elements;
3907
3908 is_reference = !grn_type_id_is_builtin(ctx, bulk.header.type);
3909
3910 element_size = grn_uvector_element_size(ctx, &bulk);
3911 elements = GRN_BULK_HEAD(&bulk);
3912 n_elements = GRN_BULK_VSIZE(&bulk) / element_size;
3913 for (i = 0; i < n_elements; i++) {
3914 uint8_t *element = elements + (element_size * i);
3915
3916 if (is_reference) {
3917 grn_id id = *((grn_id *)element);
3918 if (id == GRN_ID_NIL) {
3919 continue;
3920 }
3921 }
3922
3923 if (!grn_table_add_v_inline(ctx, res, element, element_size,
3924 &value, NULL)) {
3925 continue;
3926 }
3927
3928 grn_table_group_add_subrec(ctx, res, value,
3929 ri ? ri->score : 0,
3930 (grn_rset_posinfo *)&id, 0,
3931 calc_target,
3932 &value_buffer);
3933 }
3934 }
3935 break;
3936 case GRN_VECTOR :
3937 {
3938 unsigned int i, n_elements;
3939 n_elements = grn_vector_size(ctx, &bulk);
3940 for (i = 0; i < n_elements; i++) {
3941 const char *content;
3942 unsigned int content_length;
3943 content_length = grn_vector_get_element(ctx, &bulk, i,
3944 &content, NULL, NULL);
3945 if (grn_table_add_v_inline(ctx, res,
3946 content, content_length,
3947 &value, NULL)) {
3948 grn_table_group_add_subrec(ctx, res, value,
3949 ri ? ri->score : 0,
3950 (grn_rset_posinfo *)&id, 0,
3951 calc_target,
3952 &value_buffer);
3953 }
3954 }
3955 }
3956 break;
3957 case GRN_BULK :
3958 {
3959 if ((!idp || *((grn_id *)GRN_BULK_HEAD(&bulk))) &&
3960 grn_table_add_v_inline(ctx, res,
3961 GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
3962 &value, NULL)) {
3963 grn_table_group_add_subrec(ctx, res, value,
3964 ri ? ri->score : 0,
3965 (grn_rset_posinfo *)&id, 0,
3966 calc_target,
3967 &value_buffer);
3968 }
3969 }
3970 break;
3971 default :
3972 ERR(GRN_INVALID_ARGUMENT, "invalid column");
3973 break;
3974 }
3975 }
3976 grn_table_cursor_close(ctx, tc);
3977 }
3978 GRN_OBJ_FIN(ctx, &value_buffer);
3979 GRN_OBJ_FIN(ctx, &bulk);
3980}
3981
3982#define GRN_TABLE_GROUP_ALL_NAME "_all"
3983#define GRN_TABLE_GROUP_ALL_NAME_LEN (sizeof(GRN_TABLE_GROUP_ALL_NAME) - 1)
3984
3985static void
3986grn_table_group_all_records(grn_ctx *ctx, grn_obj *table,
3987 grn_table_group_result *result)
3988{
3989 grn_obj value_buffer;
3990 grn_table_cursor *tc;
3991 grn_obj *res = result->table;
3992 grn_obj *calc_target = result->calc_target;
3993
3994 GRN_VOID_INIT(&value_buffer);
3995 if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
3996 grn_id id;
3997 void *value;
3998 if (grn_table_add_v_inline(ctx, res,
3999 GRN_TABLE_GROUP_ALL_NAME,
4000 GRN_TABLE_GROUP_ALL_NAME_LEN,
4001 &value, NULL)) {
4002 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4003 grn_rset_recinfo *ri = NULL;
4004 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4005 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4006 }
4007 grn_table_group_add_subrec(ctx, res, value,
4008 ri ? ri->score : 0,
4009 (grn_rset_posinfo *)&id, 0,
4010 calc_target,
4011 &value_buffer);
4012 }
4013 }
4014 grn_table_cursor_close(ctx, tc);
4015 }
4016 GRN_OBJ_FIN(ctx, &value_buffer);
4017}
4018
4019grn_rc
4020grn_table_group_with_range_gap(grn_ctx *ctx, grn_obj *table,
4021 grn_table_sort_key *group_key,
4022 grn_obj *res, uint32_t range_gap)
4023{
4024 grn_obj *key = group_key->key;
4025 if (key->header.type == GRN_ACCESSOR) {
4026 grn_accessor *a = (grn_accessor *)key;
4027 if (a->action == GRN_ACCESSOR_GET_KEY &&
4028 a->next && a->next->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
4029 a->next->obj && !a->next->next) {
4030 grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
4031 int idp = GRN_OBJ_TABLEP(range);
4032 grn_table_cursor *tc;
4033 if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL,
4034 0, 0, -1, 0))) {
4035 switch (a->next->obj->header.type) {
4036 case GRN_COLUMN_FIX_SIZE :
4037 {
4038 grn_id id;
4039 grn_ra *ra = (grn_ra *)a->next->obj;
4040 unsigned int element_size = (ra)->header->element_size;
4041 grn_ra_cache cache;
4042 GRN_RA_CACHE_INIT(ra, &cache);
4043 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4044 void *v, *value;
4045 grn_id *id_;
4046 uint32_t key_size;
4047 grn_rset_recinfo *ri = NULL;
4048 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4049 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4050 }
4051 id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
4052 v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
4053 if (idp && *((grn_id *)v) &&
4054 grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
4055 continue;
4056 }
4057 if ((!idp || *((grn_id *)v))) {
4058 grn_id id;
4059 if (element_size == sizeof(uint32_t)) {
4060 uint32_t quantized = (*(uint32_t *)v);
4061 quantized -= quantized % range_gap;
4062 id = grn_table_add_v_inline(ctx, res, &quantized,
4063 element_size, &value, NULL);
4064 } else {
4065 id = grn_table_add_v_inline(ctx, res, v,
4066 element_size, &value, NULL);
4067 }
4068 if (id) {
4069 grn_table_add_subrec_inline(res, value,
4070 ri ? ri->score : 0,
4071 (grn_rset_posinfo *)&id, 0);
4072 }
4073 }
4074 }
4075 GRN_RA_CACHE_FIN(ra, &cache);
4076 }
4077 break;
4078 case GRN_COLUMN_VAR_SIZE :
4079 if (idp) { /* todo : support other type */
4080 grn_id id;
4081 grn_ja *ja = (grn_ja *)a->next->obj;
4082 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4083 grn_io_win jw;
4084 unsigned int len = 0;
4085 void *value;
4086 grn_id *v, *id_;
4087 uint32_t key_size;
4088 grn_rset_recinfo *ri = NULL;
4089 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4090 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4091 }
4092 id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
4093 if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
4094 while (len) {
4095 if ((*v != GRN_ID_NIL) &&
4096 grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
4097 grn_table_add_subrec_inline(res, value, ri ? ri->score : 0,
4098 (grn_rset_posinfo *)&id, 0);
4099 }
4100 v++;
4101 len -= sizeof(grn_id);
4102 }
4103 grn_ja_unref(ctx, &jw);
4104 }
4105 }
4106 } else {
4107 return 0;
4108 }
4109 break;
4110 default :
4111 return 0;
4112 }
4113 grn_table_cursor_close(ctx, tc);
4114 GRN_TABLE_GROUPED_ON(res);
4115 return 1;
4116 }
4117 }
4118 }
4119 return 0;
4120}
4121
4122static inline void
4123grn_table_group_multi_keys_add_record(grn_ctx *ctx,
4124 grn_table_sort_key *keys,
4125 int n_keys,
4126 grn_table_group_result *results,
4127 int n_results,
4128 grn_id id,
4129 grn_rset_recinfo *ri,
4130 grn_obj *vector,
4131 grn_obj *bulk)
4132{
4133 int r;
4134 grn_table_group_result *rp;
4135
4136 for (r = 0, rp = results; r < n_results; r++, rp++) {
4137 void *value;
4138 int i;
4139 int end;
4140
4141 if (rp->key_end > n_keys) {
4142 end = n_keys;
4143 } else {
4144 end = rp->key_end + 1;
4145 }
4146 GRN_BULK_REWIND(bulk);
4147 grn_text_benc(ctx, bulk, end - rp->key_begin);
4148 for (i = rp->key_begin; i < end; i++) {
4149 grn_section section = vector->u.v.sections[i];
4150 grn_text_benc(ctx, bulk, section.length);
4151 }
4152 {
4153 grn_obj *body = vector->u.v.body;
4154 if (body) {
4155 GRN_TEXT_PUT(ctx, bulk, GRN_BULK_HEAD(body), GRN_BULK_VSIZE(body));
4156 }
4157 }
4158 for (i = rp->key_begin; i < end; i++) {
4159 grn_section section = vector->u.v.sections[i];
4160 grn_text_benc(ctx, bulk, section.weight);
4161 grn_text_benc(ctx, bulk, section.domain);
4162 }
4163
4164 // todo : cut off GRN_ID_NIL
4165 if (grn_table_add_v_inline(ctx, rp->table,
4166 GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk),
4167 &value, NULL)) {
4168 grn_table_group_add_subrec(ctx, rp->table, value,
4169 ri ? ri->score : 0,
4170 (grn_rset_posinfo *)&id, 0,
4171 rp->calc_target,
4172 bulk);
4173 }
4174 }
4175}
4176
4177static void
4178grn_table_group_multi_keys_scalar_records(grn_ctx *ctx,
4179 grn_obj *table,
4180 grn_table_sort_key *keys,
4181 int n_keys,
4182 grn_table_group_result *results,
4183 int n_results)
4184{
4185 grn_id id;
4186 grn_table_cursor *tc;
4187 grn_obj bulk;
4188 grn_obj vector;
4189
4190 tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
4191 if (!tc) {
4192 return;
4193 }
4194
4195 GRN_TEXT_INIT(&bulk, 0);
4196 GRN_OBJ_INIT(&vector, GRN_VECTOR, 0, GRN_DB_VOID);
4197 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4198 int k;
4199 grn_table_sort_key *kp;
4200 grn_rset_recinfo *ri = NULL;
4201
4202 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4203 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4204 }
4205
4206 GRN_BULK_REWIND(&vector);
4207 for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4208 GRN_BULK_REWIND(&bulk);
4209 grn_obj_get_value(ctx, kp->key, id, &bulk);
4210 grn_vector_add_element(ctx, &vector,
4211 GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
4212 0,
4213 bulk.header.domain);
4214 }
4215
4216 grn_table_group_multi_keys_add_record(ctx, keys, n_keys, results, n_results,
4217 id, ri, &vector, &bulk);
4218 }
4219 GRN_OBJ_FIN(ctx, &vector);
4220 GRN_OBJ_FIN(ctx, &bulk);
4221 grn_table_cursor_close(ctx, tc);
4222}
4223
4224static inline void
4225grn_table_group_multi_keys_vector_record(grn_ctx *ctx,
4226 grn_table_sort_key *keys,
4227 grn_obj *key_buffers,
4228 int nth_key,
4229 int n_keys,
4230 grn_table_group_result *results,
4231 int n_results,
4232 grn_id id,
4233 grn_rset_recinfo *ri,
4234 grn_obj *vector,
4235 grn_obj *bulk)
4236{
4237 int k;
4238 grn_table_sort_key *kp;
4239
4240 for (k = nth_key, kp = &(keys[nth_key]); k < n_keys; k++, kp++) {
4241 grn_obj *key_buffer = &(key_buffers[k]);
4242 switch (key_buffer->header.type) {
4243 case GRN_UVECTOR :
4244 {
4245 unsigned int n_vector_elements;
4246 grn_id domain;
4247 grn_id *ids;
4248 unsigned int i, n_ids;
4249
4250 n_vector_elements = grn_vector_size(ctx, vector);
4251 domain = key_buffer->header.domain;
4252 ids = (grn_id *)GRN_BULK_HEAD(key_buffer);
4253 n_ids = GRN_BULK_VSIZE(key_buffer) / sizeof(grn_id);
4254 for (i = 0; i < n_ids; i++) {
4255 grn_id element_id = ids[i];
4256 grn_vector_add_element(ctx, vector,
4257 (const char *)(&element_id), sizeof(grn_id),
4258 0,
4259 domain);
4260 grn_table_group_multi_keys_vector_record(ctx,
4261 keys, key_buffers,
4262 k + 1, n_keys,
4263 results, n_results,
4264 id, ri, vector, bulk);
4265 while (grn_vector_size(ctx, vector) != n_vector_elements) {
4266 const char *content;
4267 grn_vector_pop_element(ctx, vector, &content, NULL, NULL);
4268 }
4269 }
4270 return;
4271 }
4272 break;
4273 case GRN_VECTOR :
4274 {
4275 unsigned int n_vector_elements;
4276 unsigned int i, n_key_elements;
4277
4278 n_vector_elements = grn_vector_size(ctx, vector);
4279 n_key_elements = grn_vector_size(ctx, key_buffer);
4280 for (i = 0; i < n_key_elements; i++) {
4281 const char *content;
4282 unsigned int content_length;
4283 grn_id domain;
4284 content_length = grn_vector_get_element(ctx, key_buffer, i,
4285 &content, NULL, &domain);
4286 grn_vector_add_element(ctx, vector,
4287 content, content_length,
4288 0,
4289 domain);
4290 grn_table_group_multi_keys_vector_record(ctx,
4291 keys, key_buffers,
4292 k + 1, n_keys,
4293 results, n_results,
4294 id, ri, vector, bulk);
4295 while (grn_vector_size(ctx, vector) != n_vector_elements) {
4296 grn_vector_pop_element(ctx, vector, &content, NULL, NULL);
4297 }
4298 }
4299 return;
4300 }
4301 break;
4302 default :
4303 grn_vector_add_element(ctx, vector,
4304 GRN_BULK_HEAD(key_buffer),
4305 GRN_BULK_VSIZE(key_buffer),
4306 0,
4307 key_buffer->header.domain);
4308 }
4309 }
4310
4311 if (k == n_keys) {
4312 grn_table_group_multi_keys_add_record(ctx,
4313 keys, n_keys,
4314 results, n_results,
4315 id, ri, vector, bulk);
4316 }
4317}
4318
4319static void
4320grn_table_group_multi_keys_vector_records(grn_ctx *ctx,
4321 grn_obj *table,
4322 grn_table_sort_key *keys,
4323 int n_keys,
4324 grn_table_group_result *results,
4325 int n_results)
4326{
4327 grn_id id;
4328 grn_table_cursor *tc;
4329 grn_obj bulk;
4330 grn_obj vector;
4331 grn_obj *key_buffers;
4332 int k;
4333
4334 tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
4335 if (!tc) {
4336 return;
4337 }
4338
4339 key_buffers = GRN_MALLOCN(grn_obj, n_keys);
4340 if (!key_buffers) {
4341 grn_table_cursor_close(ctx, tc);
4342 return;
4343 }
4344
4345 GRN_TEXT_INIT(&bulk, 0);
4346 GRN_OBJ_INIT(&vector, GRN_VECTOR, 0, GRN_DB_VOID);
4347 for (k = 0; k < n_keys; k++) {
4348 GRN_VOID_INIT(&(key_buffers[k]));
4349 }
4350 while ((id = grn_table_cursor_next_inline(ctx, tc))) {
4351 grn_table_sort_key *kp;
4352 grn_rset_recinfo *ri = NULL;
4353
4354 if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
4355 grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
4356 }
4357
4358 for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4359 grn_obj *key_buffer = &(key_buffers[k]);
4360 GRN_BULK_REWIND(key_buffer);
4361 grn_obj_get_value(ctx, kp->key, id, key_buffer);
4362 }
4363
4364 GRN_BULK_REWIND(&vector);
4365 grn_table_group_multi_keys_vector_record(ctx,
4366 keys, key_buffers, 0, n_keys,
4367 results, n_results,
4368 id, ri, &vector, &bulk);
4369 }
4370 for (k = 0; k < n_keys; k++) {
4371 GRN_OBJ_FIN(ctx, &(key_buffers[k]));
4372 }
4373 GRN_FREE(key_buffers);
4374 GRN_OBJ_FIN(ctx, &vector);
4375 GRN_OBJ_FIN(ctx, &bulk);
4376 grn_table_cursor_close(ctx, tc);
4377}
4378
4379grn_rc
4380grn_table_group(grn_ctx *ctx, grn_obj *table,
4381 grn_table_sort_key *keys, int n_keys,
4382 grn_table_group_result *results, int n_results)
4383{
4384 grn_rc rc = GRN_SUCCESS;
4385 grn_bool group_by_all_records = GRN_FALSE;
4386 if (n_keys == 0 && n_results == 1) {
4387 group_by_all_records = GRN_TRUE;
4388 } else if (!table || !n_keys || !n_results) {
4389 ERR(GRN_INVALID_ARGUMENT, "table or n_keys or n_results is void");
4390 return GRN_INVALID_ARGUMENT;
4391 }
4392 GRN_API_ENTER;
4393 {
4394 int k, r;
4395 grn_table_sort_key *kp;
4396 grn_table_group_result *rp;
4397 for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4398 if ((kp->flags & GRN_TABLE_GROUP_BY_COLUMN_VALUE) && !kp->key) {
4399 ERR(GRN_INVALID_ARGUMENT, "column missing in (%d)", k);
4400 goto exit;
4401 }
4402 }
4403 for (r = 0, rp = results; r < n_results; r++, rp++) {
4404 if (!rp->table) {
4405 grn_table_flags flags;
4406 grn_obj *key_type = NULL;
4407 uint32_t additional_value_size;
4408
4409 flags = GRN_TABLE_HASH_KEY|
4410 GRN_OBJ_WITH_SUBREC|
4411 GRN_OBJ_UNIT_USERDEF_DOCUMENT;
4412 if (group_by_all_records) {
4413 key_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
4414 } else if (n_keys == 1) {
4415 key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, keys[0].key));
4416 } else {
4417 flags |= GRN_OBJ_KEY_VAR_SIZE;
4418 }
4419 additional_value_size = grn_rset_recinfo_calc_values_size(ctx,
4420 rp->flags);
4421 rp->table = grn_table_create_with_max_n_subrecs(ctx, NULL, 0, NULL,
4422 flags,
4423 key_type, table,
4424 rp->max_n_subrecs,
4425 additional_value_size);
4426 if (key_type) {
4427 grn_obj_unlink(ctx, key_type);
4428 }
4429 if (!rp->table) {
4430 goto exit;
4431 }
4432 DB_OBJ(rp->table)->flags.group = rp->flags;
4433 }
4434 }
4435 if (group_by_all_records) {
4436 grn_table_group_all_records(ctx, table, results);
4437 } else if (n_keys == 1 && n_results == 1) {
4438 if (!accelerated_table_group(ctx, table, keys->key, results)) {
4439 grn_table_group_single_key_records(ctx, table, keys->key, results);
4440 }
4441 } else {
4442 grn_bool have_vector = GRN_FALSE;
4443 for (k = 0, kp = keys; k < n_keys; k++, kp++) {
4444 grn_id range_id;
4445 grn_obj_flags range_flags = 0;
4446 grn_obj_get_range_info(ctx, kp->key, &range_id, &range_flags);
4447 if (range_flags == GRN_OBJ_VECTOR) {
4448 have_vector = GRN_TRUE;
4449 break;
4450 }
4451 }
4452 if (have_vector) {
4453 grn_table_group_multi_keys_vector_records(ctx, table,
4454 keys, n_keys,
4455 results, n_results);
4456 } else {
4457 grn_table_group_multi_keys_scalar_records(ctx, table,
4458 keys, n_keys,
4459 results, n_results);
4460 }
4461 }
4462 for (r = 0, rp = results; r < n_results; r++, rp++) {
4463 GRN_TABLE_GROUPED_ON(rp->table);
4464 }
4465 }
4466exit :
4467 GRN_API_RETURN(rc);
4468}
4469
4470grn_rc
4471grn_table_setoperation(grn_ctx *ctx, grn_obj *table1, grn_obj *table2, grn_obj *res,
4472 grn_operator op)
4473{
4474 void *key = NULL, *value1 = NULL, *value2 = NULL;
4475 uint32_t value_size = 0;
4476 uint32_t key_size = 0;
4477 grn_bool have_subrec;
4478
4479 GRN_API_ENTER;
4480 if (!table1) {
4481 ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] table1 is NULL");
4482 GRN_API_RETURN(ctx->rc);
4483 }
4484 if (!table2) {
4485 ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] table2 is NULL");
4486 GRN_API_RETURN(ctx->rc);
4487 }
4488 if (!res) {
4489 ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] result table is NULL");
4490 GRN_API_RETURN(ctx->rc);
4491 }
4492
4493 if (table1 != res) {
4494 if (table2 == res) {
4495 grn_obj *t = table1;
4496 table1 = table2;
4497 table2 = t;
4498 } else {
4499 ERR(GRN_INVALID_ARGUMENT,
4500 "[table][setoperation] table1 or table2 must be result table");
4501 GRN_API_RETURN(ctx->rc);
4502 }
4503 }
4504 have_subrec = ((DB_OBJ(table1)->header.flags & GRN_OBJ_WITH_SUBREC) &&
4505 (DB_OBJ(table2)->header.flags & GRN_OBJ_WITH_SUBREC));
4506 switch (table1->header.type) {
4507 case GRN_TABLE_HASH_KEY :
4508 value_size = ((grn_hash *)table1)->value_size;
4509 break;
4510 case GRN_TABLE_PAT_KEY :
4511 value_size = ((grn_pat *)table1)->value_size;
4512 break;
4513 case GRN_TABLE_DAT_KEY :
4514 value_size = 0;
4515 break;
4516 case GRN_TABLE_NO_KEY :
4517 value_size = ((grn_array *)table1)->value_size;
4518 break;
4519 }
4520 switch (table2->header.type) {
4521 case GRN_TABLE_HASH_KEY :
4522 if (value_size < ((grn_hash *)table2)->value_size) {
4523 value_size = ((grn_hash *)table2)->value_size;
4524 }
4525 break;
4526 case GRN_TABLE_PAT_KEY :
4527 if (value_size < ((grn_pat *)table2)->value_size) {
4528 value_size = ((grn_pat *)table2)->value_size;
4529 }
4530 break;
4531 case GRN_TABLE_DAT_KEY :
4532 value_size = 0;
4533 break;
4534 case GRN_TABLE_NO_KEY :
4535 if (value_size < ((grn_array *)table2)->value_size) {
4536 value_size = ((grn_array *)table2)->value_size;
4537 }
4538 break;
4539 }
4540 switch (op) {
4541 case GRN_OP_OR :
4542 if (have_subrec) {
4543 int added;
4544 GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4545 if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, &added)) {
4546 if (added) {
4547 grn_memcpy(value1, value2, value_size);
4548 } else {
4549 grn_rset_recinfo *ri1 = value1;
4550 grn_rset_recinfo *ri2 = value2;
4551 grn_table_add_subrec_inline(table1, ri1, ri2->score, NULL, 0);
4552 }
4553 }
4554 });
4555 } else {
4556 GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4557 if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, NULL)) {
4558 grn_memcpy(value1, value2, value_size);
4559 }
4560 });
4561 }
4562 break;
4563 case GRN_OP_AND :
4564 if (have_subrec) {
4565 GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
4566 if (grn_table_get_v(ctx, table2, key, key_size, &value2)) {
4567 grn_rset_recinfo *ri1 = value1;
4568 grn_rset_recinfo *ri2 = value2;
4569 ri1->score += ri2->score;
4570 } else {
4571 _grn_table_delete_by_id(ctx, table1, id, NULL);
4572 }
4573 });
4574 } else {
4575 GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
4576 if (!grn_table_get_v(ctx, table2, key, key_size, &value2)) {
4577 _grn_table_delete_by_id(ctx, table1, id, NULL);
4578 }
4579 });
4580 }
4581 break;
4582 case GRN_OP_AND_NOT :
4583 GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4584 grn_table_delete(ctx, table1, key, key_size);
4585 });
4586 break;
4587 case GRN_OP_ADJUST :
4588 if (have_subrec) {
4589 GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4590 if (grn_table_get_v(ctx, table1, key, key_size, &value1)) {
4591 grn_rset_recinfo *ri1 = value1;
4592 grn_rset_recinfo *ri2 = value2;
4593 ri1->score += ri2->score;
4594 }
4595 });
4596 } else {
4597 GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
4598 if (grn_table_get_v(ctx, table1, key, key_size, &value1)) {
4599 grn_memcpy(value1, value2, value_size);
4600 }
4601 });
4602 }
4603 break;
4604 default :
4605 break;
4606 }
4607 GRN_API_RETURN(ctx->rc);
4608}
4609
4610grn_rc
4611grn_table_difference(grn_ctx *ctx, grn_obj *table1, grn_obj *table2,
4612 grn_obj *res1, grn_obj *res2)
4613{
4614 void *key = NULL;
4615 uint32_t key_size = 0;
4616 if (table1 != res1 || table2 != res2) { return GRN_INVALID_ARGUMENT; }
4617 if (grn_table_size(ctx, table1) > grn_table_size(ctx, table2)) {
4618 GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, NULL, {
4619 grn_id id1;
4620 if ((id1 = grn_table_get(ctx, table1, key, key_size))) {
4621 _grn_table_delete_by_id(ctx, table1, id1, NULL);
4622 _grn_table_delete_by_id(ctx, table2, id, NULL);
4623 }
4624 });
4625 } else {
4626 GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, NULL, {
4627 grn_id id2;
4628 if ((id2 = grn_table_get(ctx, table2, key, key_size))) {
4629 _grn_table_delete_by_id(ctx, table1, id, NULL);
4630 _grn_table_delete_by_id(ctx, table2, id2, NULL);
4631 }
4632 });
4633 }
4634 return GRN_SUCCESS;
4635}
4636
4637static grn_obj *grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj,
4638 const char *name, unsigned int name_size);
4639
4640static grn_obj *
4641grn_obj_column_(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
4642{
4643 grn_id table_id = DB_OBJ(table)->id;
4644 grn_obj *column = NULL;
4645
4646 if (table_id & GRN_OBJ_TMP_OBJECT) {
4647 char column_name[GRN_TABLE_MAX_KEY_SIZE];
4648 void *value = NULL;
4649 grn_snprintf(column_name, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
4650 "%u%c%.*s", table_id, GRN_DB_DELIMITER, name_size, name);
4651 grn_pat_get(ctx, ctx->impl->temporary_columns,
4652 column_name, strlen(column_name),
4653 &value);
4654 if (value) {
4655 column = *((grn_obj **)value);
4656 }
4657 } else {
4658 char buf[GRN_TABLE_MAX_KEY_SIZE];
4659 int len = grn_obj_name(ctx, table, buf, GRN_TABLE_MAX_KEY_SIZE);
4660 if (len) {
4661 buf[len++] = GRN_DB_DELIMITER;
4662 if (len + name_size <= GRN_TABLE_MAX_KEY_SIZE) {
4663 grn_memcpy(buf + len, name, name_size);
4664 column = grn_ctx_get(ctx, buf, len + name_size);
4665 } else {
4666 ERR(GRN_INVALID_ARGUMENT, "name is too long");
4667 }
4668 }
4669 }
4670
4671 return column;
4672}
4673
4674grn_obj *
4675grn_obj_column(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
4676{
4677 grn_obj *column = NULL;
4678 GRN_API_ENTER;
4679 if (GRN_OBJ_TABLEP(table)) {
4680 if (grn_db_check_name(ctx, name, name_size) ||
4681 !(column = grn_obj_column_(ctx, table, name, name_size))) {
4682 column = grn_obj_get_accessor(ctx, table, name, name_size);
4683 }
4684 } else if (GRN_ACCESSORP(table)) {
4685 column = grn_obj_get_accessor(ctx, table, name, name_size);
4686 }
4687 GRN_API_RETURN(column);
4688}
4689
4690int
4691grn_table_columns(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size,
4692 grn_obj *res)
4693{
4694 int n = 0;
4695 grn_id id;
4696
4697 GRN_API_ENTER;
4698
4699 if (!GRN_OBJ_TABLEP(table)) {
4700 GRN_API_RETURN(n);
4701 }
4702
4703 id = DB_OBJ(table)->id;
4704
4705 if (id == GRN_ID_NIL) {
4706 GRN_API_RETURN(n);
4707 }
4708
4709 if (id & GRN_OBJ_TMP_OBJECT) {
4710 char search_key[GRN_TABLE_MAX_KEY_SIZE];
4711 grn_pat_cursor *cursor;
4712 grn_snprintf(search_key, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
4713 "%u%c%.*s", id, GRN_DB_DELIMITER, name_size, name);
4714 cursor = grn_pat_cursor_open(ctx, ctx->impl->temporary_columns,
4715 search_key, strlen(search_key),
4716 NULL, 0,
4717 0, -1, GRN_CURSOR_PREFIX);
4718 if (cursor) {
4719 grn_id column_id;
4720 while ((column_id = grn_pat_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
4721 column_id |= GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN;
4722 grn_hash_add(ctx, (grn_hash *)res,
4723 &column_id, sizeof(grn_id),
4724 NULL, NULL);
4725 n++;
4726 }
4727 grn_pat_cursor_close(ctx, cursor);
4728 }
4729 } else {
4730 grn_db *s = (grn_db *)DB_OBJ(table)->db;
4731 if (s->keys) {
4732 grn_obj bulk;
4733 GRN_TEXT_INIT(&bulk, 0);
4734 grn_table_get_key2(ctx, s->keys, id, &bulk);
4735 GRN_TEXT_PUTC(ctx, &bulk, GRN_DB_DELIMITER);
4736 grn_bulk_write(ctx, &bulk, name, name_size);
4737 grn_table_search(ctx, s->keys, GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
4738 GRN_OP_PREFIX, res, GRN_OP_OR);
4739 grn_obj_close(ctx, &bulk);
4740 n = grn_table_size(ctx, res);
4741 }
4742 }
4743
4744 GRN_API_RETURN(n);
4745}
4746
4747const char *
4748_grn_table_key(grn_ctx *ctx, grn_obj *table, grn_id id, uint32_t *key_size)
4749{
4750 GRN_ASSERT(table);
4751 if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
4752 switch (table->header.type) {
4753 case GRN_TABLE_HASH_KEY :
4754 return _grn_hash_key(ctx, (grn_hash *)table, id, key_size);
4755 case GRN_TABLE_PAT_KEY :
4756 return _grn_pat_key(ctx, (grn_pat *)table, id, key_size);
4757 case GRN_TABLE_DAT_KEY :
4758 return _grn_dat_key(ctx, (grn_dat *)table, id, key_size);
4759 case GRN_TABLE_NO_KEY :
4760 {
4761 grn_array *a = (grn_array *)table;
4762 const char *v;
4763 if (a->obj.header.domain && a->value_size &&
4764 (v = _grn_array_get_value(ctx, a, id))) {
4765 *key_size = a->value_size;
4766 return v;
4767 } else {
4768 *key_size = 0;
4769 }
4770 }
4771 break;
4772 }
4773 return NULL;
4774}
4775
4776/* column */
4777
4778grn_obj *
4779grn_column_create(grn_ctx *ctx, grn_obj *table,
4780 const char *name, unsigned int name_size,
4781 const char *path, grn_column_flags flags, grn_obj *type)
4782{
4783 grn_db *s;
4784 uint32_t value_size;
4785 grn_obj *db= NULL, *res = NULL;
4786 grn_id id = GRN_ID_NIL;
4787 grn_id range = GRN_ID_NIL;
4788 grn_id domain = GRN_ID_NIL;
4789 grn_bool is_persistent_table;
4790 char fullname[GRN_TABLE_MAX_KEY_SIZE];
4791 unsigned int fullname_size;
4792 char buffer[PATH_MAX];
4793
4794 GRN_API_ENTER;
4795 if (!table) {
4796 ERR(GRN_INVALID_ARGUMENT, "[column][create] table is missing");
4797 goto exit;
4798 }
4799 if (!type) {
4800 ERR(GRN_INVALID_ARGUMENT, "[column][create] type is missing");
4801 goto exit;
4802 }
4803 if (!name || !name_size) {
4804 ERR(GRN_INVALID_ARGUMENT, "[column][create] name is missing");
4805 goto exit;
4806 }
4807 db = DB_OBJ(table)->db;
4808 s = (grn_db *)db;
4809 if (!GRN_DB_P(s)) {
4810 int table_name_len;
4811 char table_name[GRN_TABLE_MAX_KEY_SIZE];
4812 table_name_len = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
4813 ERR(GRN_INVALID_ARGUMENT,
4814 "[column][create] invalid db assigned: <%.*s>.<%.*s>",
4815 table_name_len, table_name, name_size, name);
4816 goto exit;
4817 }
4818
4819 if (grn_db_check_name(ctx, name, name_size)) {
4820 GRN_DB_CHECK_NAME_ERR("[column][create]", name, name_size);
4821 goto exit;
4822 }
4823
4824 domain = DB_OBJ(table)->id;
4825 is_persistent_table = !(domain & GRN_OBJ_TMP_OBJECT);
4826
4827 if (!domain) {
4828 ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
4829 "[column][create] [todo] table-less column isn't supported yet");
4830 goto exit;
4831 }
4832
4833 {
4834 int table_name_len;
4835 if (is_persistent_table) {
4836 table_name_len = grn_table_get_key(ctx, s->keys, domain,
4837 fullname, GRN_TABLE_MAX_KEY_SIZE);
4838 } else {
4839 grn_snprintf(fullname, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
4840 "%u", domain);
4841 table_name_len = strlen(fullname);
4842 }
4843 if (name_size + 1 + table_name_len > GRN_TABLE_MAX_KEY_SIZE) {
4844 ERR(GRN_INVALID_ARGUMENT,
4845 "[column][create] too long column name: required name_size(%d) < %d"
4846 ": <%.*s>.<%.*s>",
4847 name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - table_name_len,
4848 table_name_len, fullname, name_size, name);
4849 goto exit;
4850 }
4851 fullname[table_name_len] = GRN_DB_DELIMITER;
4852 grn_memcpy(fullname + table_name_len + 1, name, name_size);
4853 fullname_size = table_name_len + 1 + name_size;
4854 }
4855
4856 range = DB_OBJ(type)->id;
4857 switch (type->header.type) {
4858 case GRN_TYPE :
4859 {
4860 grn_db_obj *t = (grn_db_obj *)type;
4861 flags |= t->header.flags & ~GRN_OBJ_KEY_MASK;
4862 value_size = GRN_TYPE_SIZE(t);
4863 }
4864 break;
4865 case GRN_TABLE_HASH_KEY :
4866 case GRN_TABLE_PAT_KEY :
4867 case GRN_TABLE_DAT_KEY :
4868 case GRN_TABLE_NO_KEY :
4869 value_size = sizeof(grn_id);
4870 break;
4871 default :
4872 /*
4873 if (type == grn_type_any) {
4874 value_size = sizeof(grn_id) + sizeof(grn_id);
4875 }
4876 */
4877 value_size = sizeof(grn_id);
4878 }
4879
4880 if (is_persistent_table) {
4881 id = grn_obj_register(ctx, db, fullname, fullname_size);
4882 if (ERRP(ctx, GRN_ERROR)) { goto exit; }
4883
4884 {
4885 uint32_t table_name_size = 0;
4886 const char *table_name;
4887 table_name = _grn_table_key(ctx, ctx->impl->db, domain, &table_name_size);
4888 GRN_LOG(ctx, GRN_LOG_NOTICE,
4889 "DDL:%u:column_create %.*s %.*s",
4890 id,
4891 table_name_size, table_name,
4892 name_size, name);
4893 }
4894 } else {
4895 int added;
4896 id = grn_pat_add(ctx, ctx->impl->temporary_columns,
4897 fullname, fullname_size, NULL,
4898 &added);
4899 if (!id) {
4900 ERR(GRN_NO_MEMORY_AVAILABLE,
4901 "[column][create][temporary] "
4902 "failed to register temporary column name: <%.*s>",
4903 fullname_size, fullname);
4904 goto exit;
4905 } else if (!added) {
4906 id = GRN_ID_NIL;
4907 ERR(GRN_NO_MEMORY_AVAILABLE,
4908 "[column][create][temporary] already used name was assigned: <%.*s>",
4909 fullname_size, fullname);
4910 goto exit;
4911 }
4912 id |= GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN;
4913 }
4914
4915 if (is_persistent_table && flags & GRN_OBJ_PERSISTENT) {
4916 if (!path) {
4917 if (GRN_DB_PERSISTENT_P(db)) {
4918 grn_db_generate_pathname(ctx, db, id, buffer);
4919 path = buffer;
4920 } else {
4921 int table_name_len;
4922 char table_name[GRN_TABLE_MAX_KEY_SIZE];
4923 table_name_len = grn_obj_name(ctx, table, table_name,
4924 GRN_TABLE_MAX_KEY_SIZE);
4925 ERR(GRN_INVALID_ARGUMENT,
4926 "[column][create] path not assigned for persistent column"
4927 ": <%.*s>.<%.*s>",
4928 table_name_len, table_name, name_size, name);
4929 goto exit;
4930 }
4931 } else {
4932 flags |= GRN_OBJ_CUSTOM_NAME;
4933 }
4934 } else {
4935 if (path) {
4936 int table_name_len;
4937 char table_name[GRN_TABLE_MAX_KEY_SIZE];
4938 table_name_len = grn_obj_name(ctx, table, table_name,
4939 GRN_TABLE_MAX_KEY_SIZE);
4940 ERR(GRN_INVALID_ARGUMENT,
4941 "[column][create] path assigned for temporary column"
4942 ": <%.*s>.<%.*s>",
4943 table_name_len, table_name, name_size, name);
4944 goto exit;
4945 }
4946 }
4947 switch (flags & GRN_OBJ_COLUMN_TYPE_MASK) {
4948 case GRN_OBJ_COLUMN_SCALAR :
4949 if ((flags & GRN_OBJ_KEY_VAR_SIZE) || value_size > sizeof(int64_t)) {
4950 res = (grn_obj *)grn_ja_create(ctx, path, value_size, flags);
4951 } else {
4952 res = (grn_obj *)grn_ra_create(ctx, path, value_size);
4953 }
4954 break;
4955 case GRN_OBJ_COLUMN_VECTOR :
4956 res = (grn_obj *)grn_ja_create(ctx, path, value_size * 30/*todo*/, flags);
4957 //todo : zlib support
4958 break;
4959 case GRN_OBJ_COLUMN_INDEX :
4960 res = (grn_obj *)grn_ii_create(ctx, path, table, flags); //todo : ii layout support
4961 break;
4962 }
4963 if (res) {
4964 DB_OBJ(res)->header.domain = domain;
4965 DB_OBJ(res)->header.impl_flags = 0;
4966 DB_OBJ(res)->range = range;
4967 DB_OBJ(res)->header.flags = flags;
4968 res->header.flags = flags;
4969 if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
4970 _grn_obj_remove(ctx, res, GRN_FALSE);
4971 res = NULL;
4972 } else {
4973 grn_obj_touch(ctx, res, NULL);
4974 }
4975 }
4976exit :
4977 if (!res && id) { grn_obj_delete_by_id(ctx, db, id, GRN_TRUE); }
4978 GRN_API_RETURN(res);
4979}
4980
4981grn_obj *
4982grn_column_open(grn_ctx *ctx, grn_obj *table,
4983 const char *name, unsigned int name_size,
4984 const char *path, grn_obj *type)
4985{
4986 grn_id domain;
4987 grn_obj *res = NULL;
4988 grn_db *s;
4989 char fullname[GRN_TABLE_MAX_KEY_SIZE];
4990 GRN_API_ENTER;
4991 if (!table || !type || !name || !name_size) {
4992 ERR(GRN_INVALID_ARGUMENT, "missing type or name");
4993 goto exit;
4994 }
4995 s = (grn_db *)DB_OBJ(table)->db;
4996 if (!GRN_DB_P(s)) {
4997 ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
4998 goto exit;
4999 }
5000 if (grn_db_check_name(ctx, name, name_size)) {
5001 GRN_DB_CHECK_NAME_ERR("[column][open]", name, name_size);
5002 goto exit;
5003 }
5004 if ((domain = DB_OBJ(table)->id)) {
5005 int len = grn_table_get_key(ctx, s->keys, domain, fullname, GRN_TABLE_MAX_KEY_SIZE);
5006 if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
5007 ERR(GRN_INVALID_ARGUMENT, "too long column name");
5008 goto exit;
5009 }
5010 fullname[len] = GRN_DB_DELIMITER;
5011 grn_memcpy(fullname + len + 1, name, name_size);
5012 name_size += len + 1;
5013 } else {
5014 ERR(GRN_INVALID_ARGUMENT, "todo : not supported yet");
5015 goto exit;
5016 }
5017 res = grn_ctx_get(ctx, fullname, name_size);
5018 if (res) {
5019 const char *path2 = grn_obj_path(ctx, res);
5020 if (path && (!path2 || strcmp(path, path2))) { goto exit; }
5021 } else if (path) {
5022 uint32_t dbtype = grn_io_detect_type(ctx, path);
5023 if (!dbtype) { goto exit; }
5024 switch (dbtype) {
5025 case GRN_COLUMN_VAR_SIZE :
5026 res = (grn_obj *)grn_ja_open(ctx, path);
5027 break;
5028 case GRN_COLUMN_FIX_SIZE :
5029 res = (grn_obj *)grn_ra_open(ctx, path);
5030 break;
5031 case GRN_COLUMN_INDEX :
5032 res = (grn_obj *)grn_ii_open(ctx, path, table);
5033 break;
5034 }
5035 if (res) {
5036 grn_id id = grn_obj_register(ctx, (grn_obj *)s, fullname, name_size);
5037 DB_OBJ(res)->header.domain = domain;
5038 DB_OBJ(res)->range = DB_OBJ(type)->id;
5039 res->header.flags |= GRN_OBJ_CUSTOM_NAME;
5040 grn_db_obj_init(ctx, (grn_obj *)s, id, DB_OBJ(res));
5041 }
5042 }
5043exit :
5044 GRN_API_RETURN(res);
5045}
5046
5047/*
5048typedef struct {
5049 grn_id id;
5050 int flags;
5051} grn_column_set_value_arg;
5052
5053static grn_rc
5054default_column_set_value(grn_ctx *ctx, grn_proc_ctx *pctx, grn_obj *in, grn_obj *out)
5055{
5056 grn_user_data *data = grn_proc_ctx_get_local_data(pctx);
5057 if (data) {
5058 grn_column_set_value_arg *arg = data->ptr;
5059 unsigned int value_size = in->u.p.size; //todo
5060 if (!pctx->obj) { return GRN_ID_NIL; }
5061 switch (pctx->obj->header.type) {
5062 case GRN_COLUMN_VAR_SIZE :
5063 return grn_ja_put(ctx, (grn_ja *)pctx->obj, arg->id,
5064 in->u.p.ptr, value_size, 0, NULL); // todo type->flag
5065 case GRN_COLUMN_FIX_SIZE :
5066 if (((grn_ra *)pctx->obj)->header->element_size < value_size) {
5067 ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", value_size);
5068 return GRN_INVALID_ARGUMENT;
5069 } else {
5070 void *v = grn_ra_ref(ctx, (grn_ra *)pctx->obj, arg->id);
5071 if (!v) {
5072 ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
5073 return GRN_NO_MEMORY_AVAILABLE;
5074 }
5075 grn_memcpy(v, in->u.p.ptr, value_size);
5076 grn_ra_unref(ctx, (grn_ra *)pctx->obj, arg->id);
5077 }
5078 break;
5079 case GRN_COLUMN_INDEX :
5080 // todo : how??
5081 break;
5082 }
5083 return GRN_SUCCESS;
5084 } else {
5085 ERR(GRN_OBJECT_CORRUPT, "grn_proc_ctx_get_local_data failed");
5086 return ctx->rc;
5087 }
5088}
5089*/
5090
5091/**** grn_vector ****/
5092
5093//#define VECTOR(obj) ((grn_vector *)obj)
5094
5095/*
5096#define INITIAL_VECTOR_SIZE 256
5097
5098int
5099grn_vector_delimit(grn_ctx *ctx, grn_obj *vector)
5100{
5101 grn_vector *v = VECTOR(vector);
5102 uint32_t *offsets;
5103 if (!(v->n_entries & (INITIAL_VECTOR_SIZE - 1))) {
5104 offsets = GRN_REALLOC(v->offsets, sizeof(uint32_t) *
5105 (v->n_entries + INITIAL_VECTOR_SIZE));
5106 if (!offsets) { return -1; }
5107 v->offsets = offsets;
5108 }
5109 v->offsets[v->n_entries] = GRN_BULK_VSIZE(vector);
5110 return ++(v->n_entries);
5111}
5112*/
5113
5114static unsigned int
5115grn_uvector_element_size_internal(grn_ctx *ctx, grn_obj *uvector)
5116{
5117 unsigned int element_size;
5118
5119 if (IS_WEIGHT_UVECTOR(uvector)) {
5120 element_size = sizeof(weight_uvector_entry);
5121 } else {
5122 switch (uvector->header.domain) {
5123 case GRN_DB_BOOL :
5124 element_size = sizeof(grn_bool);
5125 break;
5126 case GRN_DB_INT8 :
5127 element_size = sizeof(int8_t);
5128 break;
5129 case GRN_DB_UINT8 :
5130 element_size = sizeof(uint8_t);
5131 break;
5132 case GRN_DB_INT16 :
5133 element_size = sizeof(int16_t);
5134 break;
5135 case GRN_DB_UINT16 :
5136 element_size = sizeof(uint16_t);
5137 break;
5138 case GRN_DB_INT32 :
5139 element_size = sizeof(int32_t);
5140 break;
5141 case GRN_DB_UINT32 :
5142 element_size = sizeof(uint32_t);
5143 break;
5144 case GRN_DB_INT64 :
5145 element_size = sizeof(int64_t);
5146 break;
5147 case GRN_DB_UINT64 :
5148 element_size = sizeof(uint64_t);
5149 break;
5150 case GRN_DB_FLOAT :
5151 element_size = sizeof(double);
5152 break;
5153 case GRN_DB_TIME :
5154 element_size = sizeof(int64_t);
5155 break;
5156 case GRN_DB_TOKYO_GEO_POINT :
5157 case GRN_DB_WGS84_GEO_POINT :
5158 element_size = sizeof(grn_geo_point);
5159 break;
5160 default :
5161 element_size = sizeof(grn_id);
5162 break;
5163 }
5164 }
5165
5166 return element_size;
5167}
5168
5169static unsigned int
5170grn_uvector_size_internal(grn_ctx *ctx, grn_obj *uvector)
5171{
5172 unsigned int element_size;
5173
5174 element_size = grn_uvector_element_size_internal(ctx, uvector);
5175 return GRN_BULK_VSIZE(uvector) / element_size;
5176}
5177
5178unsigned int
5179grn_vector_size(grn_ctx *ctx, grn_obj *vector)
5180{
5181 unsigned int size;
5182 if (!vector) {
5183 ERR(GRN_INVALID_ARGUMENT, "vector is null");
5184 return 0;
5185 }
5186 GRN_API_ENTER;
5187 switch (vector->header.type) {
5188 case GRN_BULK :
5189 size = GRN_BULK_VSIZE(vector);
5190 break;
5191 case GRN_UVECTOR :
5192 size = grn_uvector_size_internal(ctx, vector);
5193 break;
5194 case GRN_VECTOR :
5195 size = vector->u.v.n_sections;
5196 break;
5197 default :
5198 ERR(GRN_INVALID_ARGUMENT, "not vector");
5199 size = 0;
5200 break;
5201 }
5202 GRN_API_RETURN(size);
5203}
5204
5205static grn_obj *
5206grn_vector_body(grn_ctx *ctx, grn_obj *v)
5207{
5208 if (!v) {
5209 ERR(GRN_INVALID_ARGUMENT, "invalid argument");
5210 return NULL;
5211 }
5212 switch (v->header.type) {
5213 case GRN_VECTOR :
5214 if (!v->u.v.body) {
5215 v->u.v.body = grn_obj_open(ctx, GRN_BULK, 0, v->header.domain);
5216 }
5217 return v->u.v.body;
5218 case GRN_BULK :
5219 case GRN_UVECTOR :
5220 return v;
5221 default :
5222 return NULL;
5223 }
5224}
5225
5226unsigned int
5227grn_vector_get_element(grn_ctx *ctx, grn_obj *vector,
5228 unsigned int offset, const char **str,
5229 unsigned int *weight, grn_id *domain)
5230{
5231 unsigned int length = 0;
5232 GRN_API_ENTER;
5233 if (!vector || vector->header.type != GRN_VECTOR) {
5234 ERR(GRN_INVALID_ARGUMENT, "invalid vector");
5235 goto exit;
5236 }
5237 if (vector->u.v.n_sections <= offset) {
5238 ERR(GRN_RANGE_ERROR, "offset out of range");
5239 goto exit;
5240 }
5241 {
5242 grn_section *vp = &vector->u.v.sections[offset];
5243 grn_obj *body = grn_vector_body(ctx, vector);
5244 *str = GRN_BULK_HEAD(body) + vp->offset;
5245 if (weight) { *weight = vp->weight; }
5246 if (domain) { *domain = vp->domain; }
5247 length = vp->length;
5248 }
5249exit :
5250 GRN_API_RETURN(length);
5251}
5252
5253unsigned int
5254grn_vector_pop_element(grn_ctx *ctx, grn_obj *vector,
5255 const char **str, unsigned int *weight, grn_id *domain)
5256{
5257 unsigned int offset, length = 0;
5258 GRN_API_ENTER;
5259 if (!vector || vector->header.type != GRN_VECTOR) {
5260 ERR(GRN_INVALID_ARGUMENT, "invalid vector");
5261 goto exit;
5262 }
5263 if (!vector->u.v.n_sections) {
5264 ERR(GRN_RANGE_ERROR, "offset out of range");
5265 goto exit;
5266 }
5267 offset = --vector->u.v.n_sections;
5268 {
5269 grn_section *vp = &vector->u.v.sections[offset];
5270 grn_obj *body = grn_vector_body(ctx, vector);
5271 *str = GRN_BULK_HEAD(body) + vp->offset;
5272 if (weight) { *weight = vp->weight; }
5273 if (domain) { *domain = vp->domain; }
5274 length = vp->length;
5275 grn_bulk_truncate(ctx, body, vp->offset);
5276 }
5277exit :
5278 GRN_API_RETURN(length);
5279}
5280
5281#define W_SECTIONS_UNIT 8
5282#define S_SECTIONS_UNIT (1 << W_SECTIONS_UNIT)
5283#define M_SECTIONS_UNIT (S_SECTIONS_UNIT - 1)
5284
5285grn_rc
5286grn_vector_delimit(grn_ctx *ctx, grn_obj *v, unsigned int weight, grn_id domain)
5287{
5288 if (v->header.type != GRN_VECTOR) { return GRN_INVALID_ARGUMENT; }
5289 if (!(v->u.v.n_sections & M_SECTIONS_UNIT)) {
5290 grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
5291 (v->u.v.n_sections + S_SECTIONS_UNIT));
5292 if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
5293 v->u.v.sections = vp;
5294 }
5295 {
5296 grn_obj *body = grn_vector_body(ctx, v);
5297 grn_section *vp = &v->u.v.sections[v->u.v.n_sections];
5298 vp->offset = v->u.v.n_sections ? vp[-1].offset + vp[-1].length : 0;
5299 vp->length = GRN_BULK_VSIZE(body) - vp->offset;
5300 vp->weight = weight;
5301 vp->domain = domain;
5302 }
5303 v->u.v.n_sections++;
5304 return GRN_SUCCESS;
5305}
5306
5307grn_rc
5308grn_vector_decode(grn_ctx *ctx, grn_obj *v, const char *data, uint32_t data_size)
5309{
5310 uint8_t *p = (uint8_t *)data;
5311 uint8_t *pe = p + data_size;
5312 uint32_t n, n0 = v->u.v.n_sections;
5313 GRN_B_DEC(n, p);
5314 if (((n0 + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT) !=
5315 ((n0 + n + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT)) {
5316 grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
5317 ((n0 + n + M_SECTIONS_UNIT) & ~M_SECTIONS_UNIT));
5318 if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
5319 v->u.v.sections = vp;
5320 }
5321 {
5322 grn_section *vp;
5323 grn_obj *body = grn_vector_body(ctx, v);
5324 uint32_t offset = GRN_BULK_VSIZE(body);
5325 uint32_t o = 0, l, i;
5326 for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
5327 if (pe <= p) { return GRN_INVALID_ARGUMENT; }
5328 GRN_B_DEC(l, p);
5329 vp->length = l;
5330 vp->offset = offset + o;
5331 vp->weight = 0;
5332 vp->domain = 0;
5333 o += l;
5334 }
5335 if (pe < p + o) { return GRN_INVALID_ARGUMENT; }
5336 grn_bulk_write(ctx, body, (char *)p, o);
5337 p += o;
5338 if (p < pe) {
5339 for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
5340 if (pe <= p) { return GRN_INVALID_ARGUMENT; }
5341 GRN_B_DEC(vp->weight, p);
5342 GRN_B_DEC(vp->domain, p);
5343 }
5344 }
5345 }
5346 v->u.v.n_sections += n;
5347 return GRN_SUCCESS;
5348}
5349
5350grn_rc
5351grn_vector_add_element(grn_ctx *ctx, grn_obj *vector,
5352 const char *str, unsigned int str_len,
5353 unsigned int weight, grn_id domain)
5354{
5355 grn_obj *body;
5356 GRN_API_ENTER;
5357 if (!vector) {
5358 ERR(GRN_INVALID_ARGUMENT, "vector is null");
5359 goto exit;
5360 }
5361 if ((body = grn_vector_body(ctx, vector))) {
5362 grn_bulk_write(ctx, body, str, str_len);
5363 grn_vector_delimit(ctx, vector, weight, domain);
5364 }
5365exit :
5366 GRN_API_RETURN(ctx->rc);
5367}
5368
5369/*
5370grn_obj *
5371grn_sections_to_vector(grn_ctx *ctx, grn_obj *sections)
5372{
5373 grn_obj *vector = grn_vector_open(ctx, 0);
5374 if (vector) {
5375 grn_section *vp;
5376 int i;
5377 for (i = sections->u.v.n_sections, vp = sections->u.v.sections; i; i--, vp++) {
5378 grn_text_benc(ctx, vector, vp->weight);
5379 grn_text_benc(ctx, vector, vp->domain);
5380 grn_bulk_write(ctx, vector, vp->str, vp->str_len);
5381 grn_vector_delimit(ctx, vector);
5382 }
5383 }
5384 return vector;
5385}
5386
5387grn_obj *
5388grn_vector_to_sections(grn_ctx *ctx, grn_obj *vector, grn_obj *sections)
5389{
5390 if (!sections) {
5391 sections = grn_obj_open(ctx, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, 0);
5392 }
5393 if (sections) {
5394 int i, n = grn_vector_size(ctx, vector);
5395 sections->u.v.src = vector;
5396 for (i = 0; i < n; i++) {
5397 unsigned int size;
5398 const uint8_t *pe, *p = (uint8_t *)grn_vector_fetch(ctx, vector, i, &size);
5399 if (p) {
5400 grn_id domain;
5401 unsigned int weight;
5402 pe = p + size;
5403 if (p < pe) {
5404 GRN_B_DEC(weight, p);
5405 if (p < pe) {
5406 GRN_B_DEC(domain, p);
5407 if (p <= pe) {
5408 grn_vector_add(ctx, sections, (char *)p, pe - p, weight, domain);
5409 }
5410 }
5411 }
5412 }
5413 }
5414 }
5415 return sections;
5416}
5417*/
5418
5419/**** uvector ****/
5420
5421unsigned int
5422grn_uvector_size(grn_ctx *ctx, grn_obj *uvector)
5423{
5424 unsigned int size;
5425
5426 if (!uvector) {
5427 ERR(GRN_INVALID_ARGUMENT, "uvector must not be NULL");
5428 return 0;
5429 }
5430
5431 if (uvector->header.type != GRN_UVECTOR) {
5432 grn_obj type_name;
5433 GRN_TEXT_INIT(&type_name, 0);
5434 grn_inspect_type(ctx, &type_name, uvector->header.type);
5435 ERR(GRN_INVALID_ARGUMENT, "must be GRN_UVECTOR: %.*s",
5436 (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
5437 GRN_OBJ_FIN(ctx, &type_name);
5438 return 0;
5439 }
5440
5441 GRN_API_ENTER;
5442 size = grn_uvector_size_internal(ctx, uvector);
5443 GRN_API_RETURN(size);
5444}
5445
5446unsigned int
5447grn_uvector_element_size(grn_ctx *ctx, grn_obj *uvector)
5448{
5449 unsigned int element_size;
5450
5451 if (!uvector) {
5452 ERR(GRN_INVALID_ARGUMENT, "uvector must not be NULL");
5453 return 0;
5454 }
5455
5456 if (uvector->header.type != GRN_UVECTOR) {
5457 grn_obj type_name;
5458 GRN_TEXT_INIT(&type_name, 0);
5459 grn_inspect_type(ctx, &type_name, uvector->header.type);
5460 ERR(GRN_INVALID_ARGUMENT, "must be GRN_UVECTOR: %.*s",
5461 (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
5462 GRN_OBJ_FIN(ctx, &type_name);
5463 return 0;
5464 }
5465
5466 GRN_API_ENTER;
5467 element_size = grn_uvector_element_size_internal(ctx, uvector);
5468 GRN_API_RETURN(element_size);
5469}
5470
5471grn_rc
5472grn_uvector_add_element(grn_ctx *ctx, grn_obj *uvector,
5473 grn_id id, unsigned int weight)
5474{
5475 GRN_API_ENTER;
5476 if (!uvector) {
5477 ERR(GRN_INVALID_ARGUMENT, "uvector is null");
5478 goto exit;
5479 }
5480 if (IS_WEIGHT_UVECTOR(uvector)) {
5481 weight_uvector_entry entry;
5482 entry.id = id;
5483 entry.weight = weight;
5484 grn_bulk_write(ctx, uvector,
5485 (const char *)&entry, sizeof(weight_uvector_entry));
5486 } else {
5487 grn_bulk_write(ctx, uvector,
5488 (const char *)&id, sizeof(grn_id));
5489 }
5490exit :
5491 GRN_API_RETURN(ctx->rc);
5492}
5493
5494grn_id
5495grn_uvector_get_element(grn_ctx *ctx, grn_obj *uvector,
5496 unsigned int offset, unsigned int *weight)
5497{
5498 grn_id id = GRN_ID_NIL;
5499
5500 GRN_API_ENTER;
5501 if (!uvector || uvector->header.type != GRN_UVECTOR) {
5502 ERR(GRN_INVALID_ARGUMENT, "invalid uvector");
5503 goto exit;
5504 }
5505
5506 if (IS_WEIGHT_UVECTOR(uvector)) {
5507 const weight_uvector_entry *entry;
5508 const weight_uvector_entry *entries_start;
5509 const weight_uvector_entry *entries_end;
5510
5511 entries_start = (const weight_uvector_entry *)GRN_BULK_HEAD(uvector);
5512 entries_end = (const weight_uvector_entry *)GRN_BULK_CURR(uvector);
5513 if (offset > entries_end - entries_start) {
5514 ERR(GRN_RANGE_ERROR, "offset out of range");
5515 goto exit;
5516 }
5517
5518 entry = entries_start + offset;
5519 id = entry->id;
5520 if (weight) { *weight = entry->weight; }
5521 } else {
5522 const grn_id *ids_start;
5523 const grn_id *ids_end;
5524
5525 ids_start = (const grn_id *)GRN_BULK_HEAD(uvector);
5526 ids_end = (const grn_id *)GRN_BULK_CURR(uvector);
5527 if (offset > ids_end - ids_start) {
5528 ERR(GRN_RANGE_ERROR, "offset out of range");
5529 goto exit;
5530 }
5531 id = ids_start[offset];
5532 if (weight) { *weight = 0; }
5533 }
5534exit :
5535 GRN_API_RETURN(id);
5536}
5537
5538/**** accessor ****/
5539
5540static grn_accessor *
5541accessor_new(grn_ctx *ctx)
5542{
5543 grn_accessor *res = GRN_MALLOCN(grn_accessor, 1);
5544 if (res) {
5545 res->header.type = GRN_ACCESSOR;
5546 res->header.impl_flags = GRN_OBJ_ALLOCATED;
5547 res->header.flags = 0;
5548 res->header.domain = GRN_ID_NIL;
5549 res->range = GRN_ID_NIL;
5550 res->action = GRN_ACCESSOR_VOID;
5551 res->offset = 0;
5552 res->obj = NULL;
5553 res->next = NULL;
5554 }
5555 return res;
5556}
5557
5558inline static grn_bool
5559grn_obj_get_accessor_rset_value(grn_ctx *ctx, grn_obj *obj,
5560 grn_accessor **res, uint8_t action)
5561{
5562 grn_bool succeeded = GRN_FALSE;
5563 grn_accessor **rp;
5564
5565 for (rp = res; GRN_TRUE; rp = &(*rp)->next) {
5566 *rp = accessor_new(ctx);
5567 (*rp)->obj = obj;
5568
5569#define CHECK_GROUP_CALC_FLAG(flag) do { \
5570 if (GRN_TABLE_IS_GROUPED(obj)) { \
5571 grn_table_group_flags flags; \
5572 flags = DB_OBJ(obj)->flags.group; \
5573 if (flags & flag) { \
5574 succeeded = GRN_TRUE; \
5575 (*rp)->action = action; \
5576 goto exit; \
5577 } \
5578 } \
5579 } while(GRN_FALSE)
5580 switch (action) {
5581 case GRN_ACCESSOR_GET_SCORE :
5582 if (DB_OBJ(obj)->header.flags & GRN_OBJ_WITH_SUBREC) {
5583 (*rp)->action = action;
5584 succeeded = GRN_TRUE;
5585 goto exit;
5586 }
5587 break;
5588 case GRN_ACCESSOR_GET_MAX :
5589 CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_MAX);
5590 break;
5591 case GRN_ACCESSOR_GET_MIN :
5592 CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_MIN);
5593 break;
5594 case GRN_ACCESSOR_GET_SUM :
5595 CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_SUM);
5596 break;
5597 case GRN_ACCESSOR_GET_AVG :
5598 CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_AVG);
5599 break;
5600 case GRN_ACCESSOR_GET_NSUBRECS :
5601 if (GRN_TABLE_IS_GROUPED(obj)) {
5602 (*rp)->action = action;
5603 succeeded = GRN_TRUE;
5604 goto exit;
5605 }
5606 break;
5607 }
5608#undef CHECK_GROUP_CALC_FLAG
5609
5610 switch (obj->header.type) {
5611 case GRN_TABLE_PAT_KEY :
5612 case GRN_TABLE_DAT_KEY :
5613 case GRN_TABLE_HASH_KEY :
5614 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5615 break;
5616 case GRN_TABLE_NO_KEY :
5617 if (!obj->header.domain) {
5618 goto exit;
5619 }
5620 (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5621 break;
5622 default :
5623 /* lookup failed */
5624 goto exit;
5625 }
5626 if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5627 goto exit;
5628 }
5629 }
5630
5631exit :
5632 if (!succeeded) {
5633 grn_obj_close(ctx, (grn_obj *)*res);
5634 *res = NULL;
5635 }
5636
5637 return succeeded;
5638}
5639
5640static grn_obj *
5641grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
5642{
5643 grn_accessor *res = NULL, **rp = NULL, **rp0 = NULL;
5644 grn_bool is_chained = GRN_FALSE;
5645 if (!obj) { return NULL; }
5646 GRN_API_ENTER;
5647 if (obj->header.type == GRN_ACCESSOR) {
5648 is_chained = GRN_TRUE;
5649 for (rp0 = (grn_accessor **)&obj; *rp0; rp0 = &(*rp0)->next) {
5650 res = *rp0;
5651 }
5652 switch (res->action) {
5653 case GRN_ACCESSOR_GET_KEY :
5654 obj = grn_ctx_at(ctx, res->obj->header.domain);
5655 break;
5656 case GRN_ACCESSOR_GET_VALUE :
5657 case GRN_ACCESSOR_GET_SCORE :
5658 case GRN_ACCESSOR_GET_NSUBRECS :
5659 case GRN_ACCESSOR_GET_MAX :
5660 case GRN_ACCESSOR_GET_MIN :
5661 case GRN_ACCESSOR_GET_SUM :
5662 case GRN_ACCESSOR_GET_AVG :
5663 obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
5664 break;
5665 case GRN_ACCESSOR_GET_COLUMN_VALUE :
5666 obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
5667 break;
5668 case GRN_ACCESSOR_LOOKUP :
5669 /* todo */
5670 break;
5671 case GRN_ACCESSOR_FUNCALL :
5672 /* todo */
5673 break;
5674 }
5675 }
5676 if (!obj) {
5677 res = NULL;
5678 goto exit;
5679 }
5680 {
5681 size_t len;
5682 const char *sp, *se = name + name_size;
5683 if (*name == GRN_DB_DELIMITER) { name++; }
5684 for (sp = name; (len = grn_charlen(ctx, sp, se)); sp += len) {
5685 if (*sp == GRN_DB_DELIMITER) { break; }
5686 }
5687 if (!(len = sp - name)) { goto exit; }
5688 if (*name == GRN_DB_PSEUDO_COLUMN_PREFIX) { /* pseudo column */
5689 int done = 0;
5690 if (len < 2) { goto exit; }
5691 switch (name[1]) {
5692 case 'k' : /* key */
5693 if (len != GRN_COLUMN_NAME_KEY_LEN ||
5694 memcmp(name, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN)) {
5695 goto exit;
5696 }
5697 for (rp = &res; !done; rp = &(*rp)->next) {
5698 *rp = accessor_new(ctx);
5699 (*rp)->obj = obj;
5700 if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(obj)) {
5701 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5702 done++;
5703 break;
5704 }
5705 if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5706 grn_obj_close(ctx, (grn_obj *)res);
5707 res = NULL;
5708 goto exit;
5709 }
5710 switch (obj->header.type) {
5711 case GRN_DB :
5712 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5713 rp = &(*rp)->next;
5714 *rp = accessor_new(ctx);
5715 (*rp)->obj = obj;
5716 (*rp)->action = GRN_ACCESSOR_GET_DB_OBJ;
5717 done++;
5718 break;
5719 case GRN_TYPE :
5720 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5721 done++;
5722 break;
5723 case GRN_TABLE_PAT_KEY :
5724 case GRN_TABLE_DAT_KEY :
5725 case GRN_TABLE_HASH_KEY :
5726 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5727 break;
5728 case GRN_TABLE_NO_KEY :
5729 if (obj->header.domain) {
5730 (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5731 break;
5732 }
5733 /* fallthru */
5734 default :
5735 /* lookup failed */
5736 grn_obj_close(ctx, (grn_obj *)res);
5737 res = NULL;
5738 goto exit;
5739 }
5740 }
5741 break;
5742 case 'i' : /* id */
5743 if (len != GRN_COLUMN_NAME_ID_LEN ||
5744 memcmp(name, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN)) {
5745 goto exit;
5746 }
5747 for (rp = &res; !done; rp = &(*rp)->next) {
5748 *rp = accessor_new(ctx);
5749 (*rp)->obj = obj;
5750 if (!obj->header.domain) {
5751 (*rp)->action = GRN_ACCESSOR_GET_ID;
5752 done++;
5753 } else {
5754 if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5755 grn_obj_close(ctx, (grn_obj *)res);
5756 res = NULL;
5757 goto exit;
5758 }
5759 switch (obj->header.type) {
5760 case GRN_DB :
5761 case GRN_TYPE :
5762 (*rp)->action = GRN_ACCESSOR_GET_ID;
5763 done++;
5764 break;
5765 case GRN_TABLE_PAT_KEY :
5766 case GRN_TABLE_DAT_KEY :
5767 case GRN_TABLE_HASH_KEY :
5768 case GRN_TABLE_NO_KEY :
5769 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5770 break;
5771 default :
5772 /* lookup failed */
5773 grn_obj_close(ctx, (grn_obj *)res);
5774 res = NULL;
5775 goto exit;
5776 }
5777 }
5778 }
5779 break;
5780 case 'v' : /* value */
5781 if (len != GRN_COLUMN_NAME_VALUE_LEN ||
5782 memcmp(name, GRN_COLUMN_NAME_VALUE, GRN_COLUMN_NAME_VALUE_LEN)) {
5783 goto exit;
5784 }
5785 for (rp = &res; !done; rp = &(*rp)->next) {
5786 *rp = accessor_new(ctx);
5787 (*rp)->obj = obj;
5788 if (!obj->header.domain) {
5789 if (DB_OBJ((*rp)->obj)->range) {
5790 (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5791 done++;
5792 } else {
5793 grn_obj_close(ctx, (grn_obj *)res);
5794 res = NULL;
5795 goto exit;
5796 }
5797 done++;
5798 } else {
5799 if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
5800 grn_obj_close(ctx, (grn_obj *)res);
5801 res = NULL;
5802 goto exit;
5803 }
5804 switch (obj->header.type) {
5805 case GRN_DB :
5806 case GRN_TYPE :
5807 if (DB_OBJ((*rp)->obj)->range) {
5808 (*rp)->action = GRN_ACCESSOR_GET_VALUE;
5809 done++;
5810 } else {
5811 grn_obj_close(ctx, (grn_obj *)res);
5812 res = NULL;
5813 goto exit;
5814 }
5815 break;
5816 case GRN_TABLE_PAT_KEY :
5817 case GRN_TABLE_DAT_KEY :
5818 case GRN_TABLE_HASH_KEY :
5819 case GRN_TABLE_NO_KEY :
5820 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5821 break;
5822 default :
5823 /* lookup failed */
5824 grn_obj_close(ctx, (grn_obj *)res);
5825 res = NULL;
5826 goto exit;
5827 }
5828 }
5829 }
5830 break;
5831 case 's' : /* score, sum */
5832 if (len == GRN_COLUMN_NAME_SCORE_LEN &&
5833 memcmp(name, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN) == 0) {
5834 if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5835 GRN_ACCESSOR_GET_SCORE)) {
5836 goto exit;
5837 }
5838 } else if (len == GRN_COLUMN_NAME_SUM_LEN &&
5839 memcmp(name,
5840 GRN_COLUMN_NAME_SUM,
5841 GRN_COLUMN_NAME_SUM_LEN) == 0) {
5842 if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5843 GRN_ACCESSOR_GET_SUM)) {
5844 goto exit;
5845 }
5846 } else {
5847 goto exit;
5848 }
5849 break;
5850 case 'n' : /* nsubrecs */
5851 if (len != GRN_COLUMN_NAME_NSUBRECS_LEN ||
5852 memcmp(name,
5853 GRN_COLUMN_NAME_NSUBRECS,
5854 GRN_COLUMN_NAME_NSUBRECS_LEN)) {
5855 goto exit;
5856 }
5857 if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5858 GRN_ACCESSOR_GET_NSUBRECS)) {
5859 goto exit;
5860 }
5861 break;
5862 case 'm' : /* max, min */
5863 if (len == GRN_COLUMN_NAME_MAX_LEN &&
5864 memcmp(name,
5865 GRN_COLUMN_NAME_MAX,
5866 GRN_COLUMN_NAME_MAX_LEN) == 0) {
5867 if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5868 GRN_ACCESSOR_GET_MAX)) {
5869 goto exit;
5870 }
5871 } else if (len == GRN_COLUMN_NAME_MIN_LEN &&
5872 memcmp(name,
5873 GRN_COLUMN_NAME_MIN,
5874 GRN_COLUMN_NAME_MIN_LEN) == 0) {
5875 if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5876 GRN_ACCESSOR_GET_MIN)) {
5877 goto exit;
5878 }
5879 } else {
5880 goto exit;
5881 }
5882 break;
5883 case 'a' : /* avg */
5884 if (len == GRN_COLUMN_NAME_AVG_LEN &&
5885 memcmp(name,
5886 GRN_COLUMN_NAME_AVG,
5887 GRN_COLUMN_NAME_AVG_LEN) == 0) {
5888 if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
5889 GRN_ACCESSOR_GET_AVG)) {
5890 goto exit;
5891 }
5892 } else {
5893 goto exit;
5894 }
5895 break;
5896 default :
5897 res = NULL;
5898 goto exit;
5899 }
5900 } else {
5901 /* if obj->header.type == GRN_TYPE ... lookup table */
5902 for (rp = &res; ; rp = &(*rp)->next) {
5903 grn_obj *column = grn_obj_column_(ctx, obj, name, len);
5904 if (column) {
5905 *rp = accessor_new(ctx);
5906 (*rp)->obj = column;
5907 /*
5908 switch (column->header.type) {
5909 case GRN_COLUMN_VAR_SIZE :
5910 break;
5911 case GRN_COLUMN_FIX_SIZE :
5912 break;
5913 case GRN_COLUMN_INDEX :
5914 break;
5915 }
5916 */
5917 (*rp)->action = GRN_ACCESSOR_GET_COLUMN_VALUE;
5918 break;
5919 } else {
5920 grn_id next_obj_id;
5921 next_obj_id = obj->header.domain;
5922 if (!next_obj_id) {
5923 // ERR(GRN_INVALID_ARGUMENT, "no such column: <%s>", name);
5924 if (!is_chained) {
5925 grn_obj_close(ctx, (grn_obj *)res);
5926 }
5927 res = NULL;
5928 goto exit;
5929 }
5930 *rp = accessor_new(ctx);
5931 (*rp)->obj = obj;
5932 obj = grn_ctx_at(ctx, next_obj_id);
5933 if (!obj) {
5934 grn_obj_close(ctx, (grn_obj *)res);
5935 res = NULL;
5936 goto exit;
5937 }
5938 switch (obj->header.type) {
5939 case GRN_TABLE_PAT_KEY :
5940 case GRN_TABLE_DAT_KEY :
5941 case GRN_TABLE_HASH_KEY :
5942 case GRN_TABLE_NO_KEY :
5943 (*rp)->action = GRN_ACCESSOR_GET_KEY;
5944 break;
5945 default :
5946 /* lookup failed */
5947 grn_obj_close(ctx, (grn_obj *)res);
5948 res = NULL;
5949 goto exit;
5950 }
5951 }
5952 }
5953 }
5954 if (sp != se) {
5955 if (!grn_obj_get_accessor(ctx, (grn_obj *)res, sp, se - sp)) {
5956 if (!is_chained) {
5957 grn_obj_close(ctx, (grn_obj *)res);
5958 res = NULL;
5959 goto exit;
5960 }
5961 }
5962 }
5963 }
5964 if (rp0) { *rp0 = res; }
5965 exit :
5966 GRN_API_RETURN((grn_obj *)res);
5967}
5968
5969inline static grn_bool
5970grn_column_is_vector(grn_ctx *ctx, grn_obj *column)
5971{
5972 grn_obj_flags type;
5973
5974 if (column->header.type != GRN_COLUMN_VAR_SIZE) {
5975 return GRN_FALSE;
5976 }
5977
5978 type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
5979 return type == GRN_OBJ_COLUMN_VECTOR;
5980}
5981
5982inline static grn_bool
5983grn_column_is_index(grn_ctx *ctx, grn_obj *column)
5984{
5985 grn_obj_flags type;
5986
5987 if (column->header.type == GRN_ACCESSOR) {
5988 grn_accessor *a;
5989 for (a = (grn_accessor *)column; a; a = a->next) {
5990 if (a->next) {
5991 continue;
5992 }
5993 if (a->action != GRN_ACCESSOR_GET_COLUMN_VALUE) {
5994 return GRN_FALSE;
5995 }
5996
5997 column = a->obj;
5998 }
5999 }
6000
6001 if (column->header.type != GRN_COLUMN_INDEX) {
6002 return GRN_FALSE;
6003 }
6004
6005 type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
6006 return type == GRN_OBJ_COLUMN_INDEX;
6007}
6008
6009inline static void
6010grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj,
6011 grn_id *range_id, grn_obj_flags *range_flags)
6012{
6013 if (!obj) {
6014 *range_id = GRN_ID_NIL;
6015 } else if (grn_obj_is_proc(ctx, obj)) {
6016 /* TODO */
6017 *range_id = GRN_ID_NIL;
6018 } else if (GRN_DB_OBJP(obj)) {
6019 *range_id = DB_OBJ(obj)->range;
6020 if (grn_column_is_vector(ctx, obj)) {
6021 *range_flags = GRN_OBJ_VECTOR;
6022 }
6023 } else if (obj->header.type == GRN_ACCESSOR) {
6024 grn_accessor *a;
6025 for (a = (grn_accessor *)obj; a; a = a->next) {
6026 switch (a->action) {
6027 case GRN_ACCESSOR_GET_ID :
6028 *range_id = GRN_DB_UINT32;
6029 break;
6030 case GRN_ACCESSOR_GET_VALUE :
6031 if (GRN_DB_OBJP(a->obj)) {
6032 *range_id = DB_OBJ(a->obj)->range;
6033 }
6034 break;
6035 case GRN_ACCESSOR_GET_SCORE :
6036 *range_id = GRN_DB_FLOAT;
6037 break;
6038 case GRN_ACCESSOR_GET_NSUBRECS :
6039 *range_id = GRN_DB_INT32;
6040 break;
6041 case GRN_ACCESSOR_GET_MAX :
6042 case GRN_ACCESSOR_GET_MIN :
6043 case GRN_ACCESSOR_GET_SUM :
6044 *range_id = GRN_DB_INT64;
6045 break;
6046 case GRN_ACCESSOR_GET_AVG :
6047 *range_id = GRN_DB_FLOAT;
6048 break;
6049 case GRN_ACCESSOR_GET_COLUMN_VALUE :
6050 grn_obj_get_range_info(ctx, a->obj, range_id, range_flags);
6051 break;
6052 case GRN_ACCESSOR_GET_KEY :
6053 if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->header.domain; }
6054 break;
6055 default :
6056 if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->range; }
6057 break;
6058 }
6059 }
6060 }
6061}
6062
6063grn_id
6064grn_obj_get_range(grn_ctx *ctx, grn_obj *obj)
6065{
6066 grn_id range_id = GRN_ID_NIL;
6067 grn_obj_flags range_flags = 0;
6068
6069 grn_obj_get_range_info(ctx, obj, &range_id, &range_flags);
6070
6071 return range_id;
6072}
6073
6074int
6075grn_obj_is_persistent(grn_ctx *ctx, grn_obj *obj)
6076{
6077 int res = 0;
6078 if (GRN_DB_OBJP(obj)) {
6079 res = IS_TEMP(obj) ? 0 : 1;
6080 } else if (obj->header.type == GRN_ACCESSOR) {
6081 grn_accessor *a;
6082 for (a = (grn_accessor *)obj; a; a = a->next) {
6083 switch (a->action) {
6084 case GRN_ACCESSOR_GET_SCORE :
6085 case GRN_ACCESSOR_GET_NSUBRECS :
6086 case GRN_ACCESSOR_GET_MAX :
6087 case GRN_ACCESSOR_GET_MIN :
6088 case GRN_ACCESSOR_GET_SUM :
6089 case GRN_ACCESSOR_GET_AVG :
6090 res = 0;
6091 break;
6092 case GRN_ACCESSOR_GET_ID :
6093 case GRN_ACCESSOR_GET_VALUE :
6094 case GRN_ACCESSOR_GET_COLUMN_VALUE :
6095 case GRN_ACCESSOR_GET_KEY :
6096 if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
6097 break;
6098 default :
6099 if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
6100 break;
6101 }
6102 }
6103 }
6104 return res;
6105}
6106
6107#define SRC2RECORD() do {\
6108 grn_obj *table = grn_ctx_at(ctx, dest->header.domain);\
6109 if (GRN_OBJ_TABLEP(table)) {\
6110 grn_obj *p_key = src;\
6111 grn_id id;\
6112 if (table->header.type != GRN_TABLE_NO_KEY) {\
6113 grn_obj key;\
6114 GRN_OBJ_INIT(&key, GRN_BULK, 0, table->header.domain);\
6115 if (src->header.domain != table->header.domain) {\
6116 rc = grn_obj_cast(ctx, src, &key, GRN_TRUE);\
6117 p_key = &key;\
6118 }\
6119 if (!rc) {\
6120 if (GRN_BULK_VSIZE(p_key)) {\
6121 if (add_record_if_not_exist) {\
6122 id = grn_table_add_by_key(ctx, table, p_key, NULL);\
6123 } else {\
6124 id = grn_table_get_by_key(ctx, table, p_key);\
6125 }\
6126 if (id) {\
6127 GRN_RECORD_SET(ctx, dest, id);\
6128 } else {\
6129 rc = GRN_INVALID_ARGUMENT;\
6130 }\
6131 } else {\
6132 GRN_RECORD_SET(ctx, dest, GRN_ID_NIL);\
6133 }\
6134 }\
6135 GRN_OBJ_FIN(ctx, &key);\
6136 } else {\
6137 grn_obj record_id;\
6138 GRN_UINT32_INIT(&record_id, 0);\
6139 rc = grn_obj_cast(ctx, src, &record_id, GRN_TRUE);\
6140 if (!rc) {\
6141 id = GRN_UINT32_VALUE(&record_id);\
6142 if (id) {\
6143 GRN_RECORD_SET(ctx, dest, id);\
6144 } else {\
6145 rc = GRN_INVALID_ARGUMENT;\
6146 }\
6147 }\
6148 }\
6149 } else {\
6150 rc = GRN_FUNCTION_NOT_IMPLEMENTED;\
6151 }\
6152} while (0)
6153
6154inline static grn_rc
6155grn_obj_cast_bool(grn_ctx *ctx, grn_obj *src, grn_obj *dest,
6156 grn_bool add_record_if_not_exist)
6157{
6158 grn_rc rc = GRN_SUCCESS;
6159
6160 switch (dest->header.domain) {
6161 case GRN_DB_BOOL :
6162 GRN_BOOL_SET(ctx, dest, GRN_BOOL_VALUE(src));
6163 break;
6164 case GRN_DB_INT8 :
6165 GRN_INT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
6166 break;
6167 case GRN_DB_UINT8 :
6168 GRN_UINT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
6169 break;
6170 case GRN_DB_INT16 :
6171 GRN_INT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
6172 break;
6173 case GRN_DB_UINT16 :
6174 GRN_UINT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
6175 break;
6176 case GRN_DB_INT32 :
6177 GRN_INT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
6178 break;
6179 case GRN_DB_UINT32 :
6180 GRN_UINT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
6181 break;
6182 case GRN_DB_INT64 :
6183 GRN_INT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
6184 break;
6185 case GRN_DB_UINT64 :
6186 GRN_UINT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
6187 break;
6188 case GRN_DB_FLOAT :
6189 GRN_FLOAT_SET(ctx, dest, GRN_BOOL_VALUE(src));
6190 break;
6191 case GRN_DB_TIME :
6192 GRN_TIME_SET(ctx, dest, GRN_BOOL_VALUE(src));
6193 break;
6194 case GRN_DB_SHORT_TEXT :
6195 case GRN_DB_TEXT :
6196 case GRN_DB_LONG_TEXT :
6197 {
6198 const char *bool_text;
6199 bool_text = GRN_BOOL_VALUE(src) ? "true" : "false";
6200 GRN_TEXT_PUTS(ctx, dest, bool_text);
6201 }
6202 break;
6203 case GRN_DB_TOKYO_GEO_POINT :
6204 case GRN_DB_WGS84_GEO_POINT :
6205 rc = GRN_INVALID_ARGUMENT;
6206 break;
6207 default :
6208 SRC2RECORD();
6209 break;
6210 }
6211 return rc;
6212}
6213
6214#define NUM2DEST(getvalue,totext,tobool,totime,tofloat)\
6215 switch (dest->header.domain) {\
6216 case GRN_DB_BOOL :\
6217 tobool(ctx, dest, getvalue(src));\
6218 break;\
6219 case GRN_DB_INT8 :\
6220 GRN_INT8_SET(ctx, dest, getvalue(src));\
6221 break;\
6222 case GRN_DB_UINT8 :\
6223 GRN_UINT8_SET(ctx, dest, getvalue(src));\
6224 break;\
6225 case GRN_DB_INT16 :\
6226 GRN_INT16_SET(ctx, dest, getvalue(src));\
6227 break;\
6228 case GRN_DB_UINT16 :\
6229 GRN_UINT16_SET(ctx, dest, getvalue(src));\
6230 break;\
6231 case GRN_DB_INT32 :\
6232 GRN_INT32_SET(ctx, dest, getvalue(src));\
6233 break;\
6234 case GRN_DB_UINT32 :\
6235 GRN_UINT32_SET(ctx, dest, getvalue(src));\
6236 break;\
6237 case GRN_DB_TIME :\
6238 totime(ctx, dest, getvalue(src));\
6239 break;\
6240 case GRN_DB_INT64 :\
6241 GRN_INT64_SET(ctx, dest, getvalue(src));\
6242 break;\
6243 case GRN_DB_UINT64 :\
6244 GRN_UINT64_SET(ctx, dest, getvalue(src));\
6245 break;\
6246 case GRN_DB_FLOAT :\
6247 tofloat(ctx, dest, getvalue(src));\
6248 break;\
6249 case GRN_DB_SHORT_TEXT :\
6250 case GRN_DB_TEXT :\
6251 case GRN_DB_LONG_TEXT :\
6252 totext(ctx, dest, getvalue(src));\
6253 break;\
6254 case GRN_DB_TOKYO_GEO_POINT :\
6255 case GRN_DB_WGS84_GEO_POINT :\
6256 rc = GRN_INVALID_ARGUMENT;\
6257 break;\
6258 default :\
6259 SRC2RECORD();\
6260 break;\
6261 }
6262
6263#define TEXT2DEST(type,tonum,setvalue) do {\
6264 const char *cur, *str = GRN_TEXT_VALUE(src);\
6265 const char *str_end = GRN_BULK_CURR(src);\
6266 type i = tonum(str, str_end, &cur);\
6267 if (cur == str_end) {\
6268 setvalue(ctx, dest, i);\
6269 } else if (cur != str) {\
6270 const char *rest;\
6271 grn_obj buf;\
6272 GRN_VOID_INIT(&buf);\
6273 rc = grn_aton(ctx, str, str_end, &rest, &buf);\
6274 if (!rc) {\
6275 rc = grn_obj_cast(ctx, &buf, dest, add_record_if_not_exist);\
6276 }\
6277 GRN_OBJ_FIN(ctx, &buf);\
6278 } else {\
6279 rc = GRN_INVALID_ARGUMENT;\
6280 }\
6281} while (0)
6282
6283#define NUM2BOOL(ctx, dest, value) GRN_BOOL_SET(ctx, dest, value != 0)
6284#define FLOAT2BOOL(ctx, dest, value) do {\
6285 double value_ = value;\
6286 GRN_BOOL_SET(ctx, dest, value_ < -DBL_EPSILON || DBL_EPSILON < value_);\
6287} while (0)
6288
6289#define NUM2TIME(ctx, dest, value)\
6290 GRN_TIME_SET(ctx, dest, (long long int)(value) * GRN_TIME_USEC_PER_SEC);
6291#define TIME2TIME(ctx, dest, value)\
6292 GRN_TIME_SET(ctx, dest, value);
6293#define FLOAT2TIME(ctx, dest, value) do {\
6294 int64_t usec = llround(value * GRN_TIME_USEC_PER_SEC);\
6295 GRN_TIME_SET(ctx, dest, usec);\
6296} while (0)
6297
6298#define NUM2FLOAT(ctx, dest, value)\
6299 GRN_FLOAT_SET(ctx, dest, value);
6300#define TIME2FLOAT(ctx, dest, value)\
6301 GRN_FLOAT_SET(ctx, dest, (double)(value) / GRN_TIME_USEC_PER_SEC);
6302#define FLOAT2FLOAT(ctx, dest, value)\
6303 GRN_FLOAT_SET(ctx, dest, value);
6304
6305static grn_rc
6306grn_obj_cast_record(grn_ctx *ctx,
6307 grn_obj *src,
6308 grn_obj *dest,
6309 grn_bool add_record_if_not_exist)
6310{
6311 grn_obj *src_table;
6312 grn_obj *dest_table;
6313 const char *key;
6314 uint32_t key_size;
6315 grn_id dest_id;
6316
6317 if (src->header.domain == dest->header.domain) {
6318 GRN_RECORD_SET(ctx, dest, GRN_RECORD_VALUE(src));
6319 return GRN_SUCCESS;
6320 }
6321
6322 src_table = grn_ctx_at(ctx, src->header.domain);
6323 if (!src_table) {
6324 return GRN_INVALID_ARGUMENT;
6325 }
6326 if (src_table->header.type == GRN_TABLE_NO_KEY) {
6327 return GRN_INVALID_ARGUMENT;
6328 }
6329
6330 dest_table = grn_ctx_at(ctx, dest->header.domain);
6331 if (!dest_table) {
6332 return GRN_INVALID_ARGUMENT;
6333 }
6334 switch (dest_table->header.type) {
6335 case GRN_TABLE_HASH_KEY :
6336 case GRN_TABLE_PAT_KEY :
6337 case GRN_TABLE_DAT_KEY :
6338 break;
6339 default :
6340 return GRN_INVALID_ARGUMENT;
6341 }
6342
6343 if (GRN_RECORD_VALUE(src) == GRN_ID_NIL) {
6344 GRN_RECORD_SET(ctx, dest, GRN_RECORD_VALUE(src));
6345 return GRN_SUCCESS;
6346 }
6347
6348 key = _grn_table_key(ctx, src_table, GRN_RECORD_VALUE(src), &key_size);
6349 if (add_record_if_not_exist) {
6350 dest_id = grn_table_add(ctx, dest_table, key, key_size, NULL);
6351 } else {
6352 dest_id = grn_table_get(ctx, dest_table, key, key_size);
6353 }
6354 GRN_RECORD_SET(ctx, dest, dest_id);
6355 return GRN_SUCCESS;
6356}
6357
6358grn_rc
6359grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest,
6360 grn_bool add_record_if_not_exist)
6361{
6362 grn_rc rc = GRN_SUCCESS;
6363 switch (src->header.domain) {
6364 case GRN_DB_BOOL :
6365 rc = grn_obj_cast_bool(ctx, src, dest, add_record_if_not_exist);
6366 break;
6367 case GRN_DB_INT8 :
6368 NUM2DEST(GRN_INT8_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6369 break;
6370 case GRN_DB_UINT8 :
6371 NUM2DEST(GRN_UINT8_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6372 break;
6373 case GRN_DB_INT16 :
6374 NUM2DEST(GRN_INT16_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6375 break;
6376 case GRN_DB_UINT16 :
6377 NUM2DEST(GRN_UINT16_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6378 break;
6379 case GRN_DB_INT32 :
6380 NUM2DEST(GRN_INT32_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6381 break;
6382 case GRN_DB_UINT32 :
6383 NUM2DEST(GRN_UINT32_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6384 break;
6385 case GRN_DB_INT64 :
6386 NUM2DEST(GRN_INT64_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6387 break;
6388 case GRN_DB_TIME :
6389 NUM2DEST(GRN_TIME_VALUE, grn_text_lltoa, NUM2BOOL, TIME2TIME, TIME2FLOAT);
6390 break;
6391 case GRN_DB_UINT64 :
6392 NUM2DEST(GRN_UINT64_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
6393 break;
6394 case GRN_DB_FLOAT :
6395 NUM2DEST(GRN_FLOAT_VALUE, grn_text_ftoa, FLOAT2BOOL, FLOAT2TIME,
6396 FLOAT2FLOAT);
6397 break;
6398 case GRN_DB_SHORT_TEXT :
6399 case GRN_DB_TEXT :
6400 case GRN_DB_LONG_TEXT :
6401 switch (dest->header.domain) {
6402 case GRN_DB_BOOL :
6403 GRN_BOOL_SET(ctx, dest, GRN_TEXT_LEN(src) > 0);
6404 break;
6405 case GRN_DB_INT8 :
6406 TEXT2DEST(int8_t, grn_atoi8, GRN_INT8_SET);
6407 break;
6408 case GRN_DB_UINT8 :
6409 TEXT2DEST(uint8_t, grn_atoui8, GRN_UINT8_SET);
6410 break;
6411 case GRN_DB_INT16 :
6412 TEXT2DEST(int16_t, grn_atoi16, GRN_INT16_SET);
6413 break;
6414 case GRN_DB_UINT16 :
6415 TEXT2DEST(uint16_t, grn_atoui16, GRN_UINT16_SET);
6416 break;
6417 case GRN_DB_INT32 :
6418 TEXT2DEST(int32_t, grn_atoi, GRN_INT32_SET);
6419 break;
6420 case GRN_DB_UINT32 :
6421 TEXT2DEST(uint32_t, grn_atoui, GRN_UINT32_SET);
6422 break;
6423 case GRN_DB_TIME :
6424 {
6425 grn_timeval v;
6426 int len = GRN_TEXT_LEN(src);
6427 char *str = GRN_TEXT_VALUE(src);
6428 if (grn_str2timeval(str, len, &v)) {
6429 double d;
6430 char *end;
6431 grn_obj buf;
6432 GRN_TEXT_INIT(&buf, 0);
6433 GRN_TEXT_PUT(ctx, &buf, str, len);
6434 GRN_TEXT_PUTC(ctx, &buf, '\0');
6435 errno = 0;
6436 d = strtod(GRN_TEXT_VALUE(&buf), &end);
6437 if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
6438 v.tv_sec = d;
6439 v.tv_nsec = ((d - v.tv_sec) * GRN_TIME_NSEC_PER_SEC);
6440 } else {
6441 rc = GRN_INVALID_ARGUMENT;
6442 }
6443 GRN_OBJ_FIN(ctx, &buf);
6444 }
6445 GRN_TIME_SET(ctx, dest,
6446 GRN_TIME_PACK((int64_t)v.tv_sec,
6447 GRN_TIME_NSEC_TO_USEC(v.tv_nsec)));
6448 }
6449 break;
6450 case GRN_DB_INT64 :
6451 TEXT2DEST(int64_t, grn_atoll, GRN_INT64_SET);
6452 break;
6453 case GRN_DB_UINT64 :
6454 TEXT2DEST(int64_t, grn_atoll, GRN_UINT64_SET);
6455 break;
6456 case GRN_DB_FLOAT :
6457 {
6458 double d;
6459 char *end;
6460 grn_obj buf;
6461 GRN_TEXT_INIT(&buf, 0);
6462 GRN_TEXT_PUT(ctx, &buf, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
6463 GRN_TEXT_PUTC(ctx, &buf, '\0');
6464 errno = 0;
6465 d = strtod(GRN_TEXT_VALUE(&buf), &end);
6466 if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
6467 GRN_FLOAT_SET(ctx, dest, d);
6468 } else {
6469 rc = GRN_INVALID_ARGUMENT;
6470 }
6471 GRN_OBJ_FIN(ctx, &buf);
6472 }
6473 break;
6474 case GRN_DB_SHORT_TEXT :
6475 case GRN_DB_TEXT :
6476 case GRN_DB_LONG_TEXT :
6477 GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
6478 break;
6479 case GRN_DB_TOKYO_GEO_POINT :
6480 case GRN_DB_WGS84_GEO_POINT :
6481 {
6482 int latitude, longitude;
6483 double degree;
6484 const char *cur, *str = GRN_TEXT_VALUE(src);
6485 const char *str_end = GRN_BULK_CURR(src);
6486 if (str == str_end) {
6487 GRN_GEO_POINT_SET(ctx, dest, 0, 0);
6488 } else {
6489 char *end;
6490 grn_obj buf, *buf_p = NULL;
6491 latitude = grn_atoi(str, str_end, &cur);
6492 if (cur < str_end && cur[0] == '.') {
6493 GRN_TEXT_INIT(&buf, 0);
6494 GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
6495 GRN_TEXT_PUTC(ctx, &buf, '\0');
6496 buf_p = &buf;
6497 errno = 0;
6498 degree = strtod(GRN_TEXT_VALUE(buf_p), &end);
6499 if (errno) {
6500 rc = GRN_INVALID_ARGUMENT;
6501 } else {
6502 latitude = GRN_GEO_DEGREE2MSEC(degree);
6503 cur = str + (end - GRN_TEXT_VALUE(buf_p));
6504 }
6505 }
6506 if (!rc && (cur[0] == 'x' || cur[0] == ',') && cur + 1 < str_end) {
6507 const char *c = cur + 1;
6508 longitude = grn_atoi(c, str_end, &cur);
6509 if (cur < str_end && cur[0] == '.') {
6510 if (!buf_p) {
6511 GRN_TEXT_INIT(&buf, 0);
6512 GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
6513 GRN_TEXT_PUTC(ctx, &buf, '\0');
6514 buf_p = &buf;
6515 }
6516 errno = 0;
6517 degree = strtod(GRN_TEXT_VALUE(buf_p) + (c - str), &end);
6518 if (errno) {
6519 rc = GRN_INVALID_ARGUMENT;
6520 } else {
6521 longitude = GRN_GEO_DEGREE2MSEC(degree);
6522 cur = str + (end - GRN_TEXT_VALUE(buf_p));
6523 }
6524 }
6525 if (!rc && cur == str_end) {
6526 if ((GRN_GEO_MIN_LATITUDE <= latitude &&
6527 latitude <= GRN_GEO_MAX_LATITUDE) &&
6528 (GRN_GEO_MIN_LONGITUDE <= longitude &&
6529 longitude <= GRN_GEO_MAX_LONGITUDE)) {
6530 GRN_GEO_POINT_SET(ctx, dest, latitude, longitude);
6531 } else {
6532 rc = GRN_INVALID_ARGUMENT;
6533 }
6534 } else {
6535 rc = GRN_INVALID_ARGUMENT;
6536 }
6537 } else {
6538 rc = GRN_INVALID_ARGUMENT;
6539 }
6540 if (buf_p) { GRN_OBJ_FIN(ctx, buf_p); }
6541 }
6542 }
6543 break;
6544 default :
6545 SRC2RECORD();
6546 break;
6547 }
6548 break;
6549 case GRN_DB_TOKYO_GEO_POINT :
6550 case GRN_DB_WGS84_GEO_POINT :
6551 if (src->header.domain == dest->header.domain) {
6552 GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
6553 } else {
6554 int latitude, longitude;
6555 double latitude_in_degree, longitude_in_degree;
6556 GRN_GEO_POINT_VALUE(src, latitude, longitude);
6557 latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
6558 longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
6559 /* TokyoGeoPoint <-> WGS84GeoPoint is based on
6560 http://www.jalan.net/jw/jwp0200/jww0203.do
6561
6562 jx: longitude in degree in Tokyo Geodetic System.
6563 jy: latitude in degree in Tokyo Geodetic System.
6564 wx: longitude in degree in WGS 84.
6565 wy: latitude in degree in WGS 84.
6566
6567 jy = wy * 1.000106961 - wx * 0.000017467 - 0.004602017
6568 jx = wx * 1.000083049 + wy * 0.000046047 - 0.010041046
6569
6570 wy = jy - jy * 0.00010695 + jx * 0.000017464 + 0.0046017
6571 wx = jx - jy * 0.000046038 - jx * 0.000083043 + 0.010040
6572 */
6573 if (dest->header.domain == GRN_DB_TOKYO_GEO_POINT) {
6574 double wgs84_latitude_in_degree = latitude_in_degree;
6575 double wgs84_longitude_in_degree = longitude_in_degree;
6576 int tokyo_latitude, tokyo_longitude;
6577 double tokyo_latitude_in_degree, tokyo_longitude_in_degree;
6578 tokyo_latitude_in_degree =
6579 wgs84_latitude_in_degree * 1.000106961 -
6580 wgs84_longitude_in_degree * 0.000017467 -
6581 0.004602017;
6582 tokyo_longitude_in_degree =
6583 wgs84_longitude_in_degree * 1.000083049 +
6584 wgs84_latitude_in_degree * 0.000046047 -
6585 0.010041046;
6586 tokyo_latitude = GRN_GEO_DEGREE2MSEC(tokyo_latitude_in_degree);
6587 tokyo_longitude = GRN_GEO_DEGREE2MSEC(tokyo_longitude_in_degree);
6588 GRN_GEO_POINT_SET(ctx, dest, tokyo_latitude, tokyo_longitude);
6589 } else {
6590 double tokyo_latitude_in_degree = latitude_in_degree;
6591 double tokyo_longitude_in_degree = longitude_in_degree;
6592 int wgs84_latitude, wgs84_longitude;
6593 double wgs84_latitude_in_degree, wgs84_longitude_in_degree;
6594 wgs84_latitude_in_degree =
6595 tokyo_latitude_in_degree -
6596 tokyo_latitude_in_degree * 0.00010695 +
6597 tokyo_longitude_in_degree * 0.000017464 +
6598 0.0046017;
6599 wgs84_longitude_in_degree =
6600 tokyo_longitude_in_degree -
6601 tokyo_latitude_in_degree * 0.000046038 -
6602 tokyo_longitude_in_degree * 0.000083043 +
6603 0.010040;
6604 wgs84_latitude = GRN_GEO_DEGREE2MSEC(wgs84_latitude_in_degree);
6605 wgs84_longitude = GRN_GEO_DEGREE2MSEC(wgs84_longitude_in_degree);
6606 GRN_GEO_POINT_SET(ctx, dest, wgs84_latitude, wgs84_longitude);
6607 }
6608 }
6609 break;
6610 case GRN_VOID :
6611 rc = grn_obj_reinit(ctx, dest, dest->header.domain, dest->header.flags);
6612 break;
6613 default :
6614 if (src->header.domain >= GRN_N_RESERVED_TYPES) {
6615 grn_obj *table;
6616 table = grn_ctx_at(ctx, src->header.domain);
6617 switch (table->header.type) {
6618 case GRN_TABLE_HASH_KEY :
6619 case GRN_TABLE_PAT_KEY :
6620 case GRN_TABLE_DAT_KEY :
6621 case GRN_TABLE_NO_KEY :
6622 rc = grn_obj_cast_record(ctx, src, dest, add_record_if_not_exist);
6623 break;
6624 default :
6625 rc = GRN_FUNCTION_NOT_IMPLEMENTED;
6626 break;
6627 }
6628 } else {
6629 rc = GRN_FUNCTION_NOT_IMPLEMENTED;
6630 }
6631 break;
6632 }
6633 return rc;
6634}
6635
6636const char *
6637grn_accessor_get_value_(grn_ctx *ctx, grn_accessor *a, grn_id id, uint32_t *size)
6638{
6639 const char *value = NULL;
6640 for (;;) {
6641 switch (a->action) {
6642 case GRN_ACCESSOR_GET_ID :
6643 value = (const char *)(uintptr_t)id;
6644 *size = GRN_OBJ_GET_VALUE_IMD;
6645 break;
6646 case GRN_ACCESSOR_GET_KEY :
6647 value = _grn_table_key(ctx, a->obj, id, size);
6648 break;
6649 case GRN_ACCESSOR_GET_VALUE :
6650 value = grn_obj_get_value_(ctx, a->obj, id, size);
6651 break;
6652 case GRN_ACCESSOR_GET_SCORE :
6653 if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6654 value = (const char *)&((grn_rset_recinfo *)value)->score;
6655 *size = sizeof(double);
6656 }
6657 break;
6658 case GRN_ACCESSOR_GET_NSUBRECS :
6659 if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6660 value = (const char *)&((grn_rset_recinfo *)value)->n_subrecs;
6661 *size = sizeof(int);
6662 }
6663 break;
6664 case GRN_ACCESSOR_GET_MAX :
6665 if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6666 value =
6667 (const char *)grn_rset_recinfo_get_max_(ctx,
6668 (grn_rset_recinfo *)value,
6669 a->obj);
6670 *size = GRN_RSET_MAX_SIZE;
6671 }
6672 break;
6673 case GRN_ACCESSOR_GET_MIN :
6674 if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6675 value =
6676 (const char *)grn_rset_recinfo_get_min_(ctx,
6677 (grn_rset_recinfo *)value,
6678 a->obj);
6679 *size = GRN_RSET_MIN_SIZE;
6680 }
6681 break;
6682 case GRN_ACCESSOR_GET_SUM :
6683 if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6684 value =
6685 (const char *)grn_rset_recinfo_get_sum_(ctx,
6686 (grn_rset_recinfo *)value,
6687 a->obj);
6688 *size = GRN_RSET_SUM_SIZE;
6689 }
6690 break;
6691 case GRN_ACCESSOR_GET_AVG :
6692 if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
6693 value =
6694 (const char *)grn_rset_recinfo_get_avg_(ctx,
6695 (grn_rset_recinfo *)value,
6696 a->obj);
6697 *size = GRN_RSET_AVG_SIZE;
6698 }
6699 break;
6700 case GRN_ACCESSOR_GET_COLUMN_VALUE :
6701 /* todo : support vector */
6702 value = grn_obj_get_value_(ctx, a->obj, id, size);
6703 break;
6704 case GRN_ACCESSOR_GET_DB_OBJ :
6705 value = _grn_table_key(ctx, ((grn_db *)ctx->impl->db)->keys, id, size);
6706 break;
6707 case GRN_ACCESSOR_LOOKUP :
6708 /* todo */
6709 break;
6710 case GRN_ACCESSOR_FUNCALL :
6711 /* todo */
6712 break;
6713 }
6714 if (value && (a = a->next)) {
6715 id = *((grn_id *)value);
6716 } else {
6717 break;
6718 }
6719 }
6720 return value;
6721}
6722
6723static grn_obj *
6724grn_accessor_get_value(grn_ctx *ctx, grn_accessor *a, grn_id id, grn_obj *value)
6725{
6726 uint32_t vs = 0;
6727 uint32_t size0;
6728 void *vp = NULL;
6729 if (!value) {
6730 if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) { return NULL; }
6731 } else {
6732 value->header.type = GRN_BULK;
6733 }
6734 size0 = GRN_BULK_VSIZE(value);
6735 for (;;) {
6736 grn_bulk_truncate(ctx, value, size0);
6737 switch (a->action) {
6738 case GRN_ACCESSOR_GET_ID :
6739 GRN_UINT32_PUT(ctx, value, id);
6740 value->header.domain = GRN_DB_UINT32;
6741 vp = GRN_BULK_HEAD(value) + size0;
6742 vs = GRN_BULK_VSIZE(value) - size0;
6743 break;
6744 case GRN_ACCESSOR_GET_KEY :
6745 if (!a->next && GRN_TABLE_IS_MULTI_KEYS_GROUPED(a->obj)) {
6746 grn_obj_ensure_vector(ctx, value);
6747 if (id) {
6748 grn_obj raw_vector;
6749 GRN_TEXT_INIT(&raw_vector, 0);
6750 grn_table_get_key2(ctx, a->obj, id, &raw_vector);
6751 grn_vector_decode(ctx, value,
6752 GRN_BULK_HEAD(&raw_vector),
6753 GRN_BULK_VSIZE(&raw_vector));
6754 GRN_OBJ_FIN(ctx, &raw_vector);
6755 }
6756 vp = NULL;
6757 vs = 0;
6758 } else {
6759 if (id) {
6760 grn_table_get_key2(ctx, a->obj, id, value);
6761 vp = GRN_BULK_HEAD(value) + size0;
6762 vs = GRN_BULK_VSIZE(value) - size0;
6763 } else {
6764 vp = NULL;
6765 vs = 0;
6766 }
6767 value->header.domain = a->obj->header.domain;
6768 }
6769 break;
6770 case GRN_ACCESSOR_GET_VALUE :
6771 grn_obj_get_value(ctx, a->obj, id, value);
6772 vp = GRN_BULK_HEAD(value) + size0;
6773 vs = GRN_BULK_VSIZE(value) - size0;
6774 break;
6775 case GRN_ACCESSOR_GET_SCORE :
6776 if (id) {
6777 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6778 GRN_FLOAT_PUT(ctx, value, ri->score);
6779 } else {
6780 GRN_FLOAT_PUT(ctx, value, 0.0);
6781 }
6782 value->header.domain = GRN_DB_FLOAT;
6783 break;
6784 case GRN_ACCESSOR_GET_NSUBRECS :
6785 if (id) {
6786 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6787 GRN_INT32_PUT(ctx, value, ri->n_subrecs);
6788 } else {
6789 GRN_INT32_PUT(ctx, value, 0);
6790 }
6791 value->header.domain = GRN_DB_INT32;
6792 break;
6793 case GRN_ACCESSOR_GET_MAX :
6794 if (id) {
6795 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6796 int64_t max;
6797 max = grn_rset_recinfo_get_max(ctx, ri, a->obj);
6798 GRN_INT64_PUT(ctx, value, max);
6799 } else {
6800 GRN_INT64_PUT(ctx, value, 0);
6801 }
6802 value->header.domain = GRN_DB_INT64;
6803 break;
6804 case GRN_ACCESSOR_GET_MIN :
6805 if (id) {
6806 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6807 int64_t min;
6808 min = grn_rset_recinfo_get_min(ctx, ri, a->obj);
6809 GRN_INT64_PUT(ctx, value, min);
6810 } else {
6811 GRN_INT64_PUT(ctx, value, 0);
6812 }
6813 value->header.domain = GRN_DB_INT64;
6814 break;
6815 case GRN_ACCESSOR_GET_SUM :
6816 if (id) {
6817 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6818 int64_t sum;
6819 sum = grn_rset_recinfo_get_sum(ctx, ri, a->obj);
6820 GRN_INT64_PUT(ctx, value, sum);
6821 } else {
6822 GRN_INT64_PUT(ctx, value, 0);
6823 }
6824 value->header.domain = GRN_DB_INT64;
6825 break;
6826 case GRN_ACCESSOR_GET_AVG :
6827 if (id) {
6828 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
6829 double avg;
6830 avg = grn_rset_recinfo_get_avg(ctx, ri, a->obj);
6831 GRN_FLOAT_PUT(ctx, value, avg);
6832 } else {
6833 GRN_FLOAT_PUT(ctx, value, 0.0);
6834 }
6835 value->header.domain = GRN_DB_FLOAT;
6836 break;
6837 case GRN_ACCESSOR_GET_COLUMN_VALUE :
6838 /* todo : support vector */
6839 grn_obj_get_value(ctx, a->obj, id, value);
6840 vp = GRN_BULK_HEAD(value) + size0;
6841 vs = GRN_BULK_VSIZE(value) - size0;
6842 break;
6843 case GRN_ACCESSOR_GET_DB_OBJ :
6844 value = grn_ctx_at(ctx, id);
6845 grn_obj_close(ctx, value);
6846 return value;
6847 break;
6848 case GRN_ACCESSOR_LOOKUP :
6849 /* todo */
6850 break;
6851 case GRN_ACCESSOR_FUNCALL :
6852 /* todo */
6853 break;
6854 }
6855 if ((a = a->next)) {
6856 if (vs > 0) {
6857 id = *((grn_id *)vp);
6858 } else {
6859 id = GRN_ID_NIL;
6860 }
6861 } else {
6862 break;
6863 }
6864 }
6865 return value;
6866}
6867
6868static grn_rc
6869grn_accessor_set_value(grn_ctx *ctx, grn_accessor *a, grn_id id,
6870 grn_obj *value, int flags)
6871{
6872 grn_rc rc = GRN_SUCCESS;
6873 if (!value) { value = grn_obj_open(ctx, GRN_BULK, 0, 0); }
6874 if (value) {
6875 grn_obj buf;
6876 void *vp = NULL;
6877 GRN_TEXT_INIT(&buf, 0);
6878 for (;;) {
6879 GRN_BULK_REWIND(&buf);
6880 switch (a->action) {
6881 case GRN_ACCESSOR_GET_KEY :
6882 grn_table_get_key2(ctx, a->obj, id, &buf);
6883 vp = GRN_BULK_HEAD(&buf);
6884 break;
6885 case GRN_ACCESSOR_GET_VALUE :
6886 if (a->next) {
6887 grn_obj_get_value(ctx, a->obj, id, &buf);
6888 vp = GRN_BULK_HEAD(&buf);
6889 } else {
6890 rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
6891 }
6892 break;
6893 case GRN_ACCESSOR_GET_SCORE :
6894 {
6895 grn_rset_recinfo *ri;
6896 if (a->next) {
6897 grn_obj_get_value(ctx, a->obj, id, &buf);
6898 ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6899 vp = &ri->score;
6900 } else {
6901 uint32_t size;
6902 if ((ri = (grn_rset_recinfo *) grn_obj_get_value_(ctx, a->obj, id, &size))) {
6903 // todo : flags support
6904 if (value->header.domain == GRN_DB_FLOAT) {
6905 ri->score = GRN_FLOAT_VALUE(value);
6906 } else {
6907 grn_obj buf;
6908 GRN_FLOAT_INIT(&buf, 0);
6909 grn_obj_cast(ctx, value, &buf, GRN_FALSE);
6910 ri->score = GRN_FLOAT_VALUE(&buf);
6911 GRN_OBJ_FIN(ctx, &buf);
6912 }
6913 }
6914 }
6915 }
6916 break;
6917 case GRN_ACCESSOR_GET_NSUBRECS :
6918 grn_obj_get_value(ctx, a->obj, id, &buf);
6919 {
6920 grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6921 vp = &ri->n_subrecs;
6922 }
6923 break;
6924 case GRN_ACCESSOR_GET_MAX :
6925 grn_obj_get_value(ctx, a->obj, id, &buf);
6926 {
6927 grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6928 if (value->header.type == GRN_DB_INT64) {
6929 grn_rset_recinfo_set_max(ctx, ri, a->obj, GRN_INT64_VALUE(value));
6930 } else {
6931 grn_obj value_int64;
6932 GRN_INT64_INIT(&value_int64, 0);
6933 if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
6934 grn_rset_recinfo_set_max(ctx, ri, a->obj,
6935 GRN_INT64_VALUE(&value_int64));
6936 }
6937 GRN_OBJ_FIN(ctx, &value_int64);
6938 }
6939 }
6940 break;
6941 case GRN_ACCESSOR_GET_MIN :
6942 grn_obj_get_value(ctx, a->obj, id, &buf);
6943 {
6944 grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6945 if (value->header.type == GRN_DB_INT64) {
6946 grn_rset_recinfo_set_min(ctx, ri, a->obj, GRN_INT64_VALUE(value));
6947 } else {
6948 grn_obj value_int64;
6949 GRN_INT64_INIT(&value_int64, 0);
6950 if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
6951 grn_rset_recinfo_set_min(ctx, ri, a->obj,
6952 GRN_INT64_VALUE(&value_int64));
6953 }
6954 GRN_OBJ_FIN(ctx, &value_int64);
6955 }
6956 }
6957 break;
6958 case GRN_ACCESSOR_GET_SUM :
6959 grn_obj_get_value(ctx, a->obj, id, &buf);
6960 {
6961 grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6962 if (value->header.type == GRN_DB_INT64) {
6963 grn_rset_recinfo_set_sum(ctx, ri, a->obj, GRN_INT64_VALUE(value));
6964 } else {
6965 grn_obj value_int64;
6966 GRN_INT64_INIT(&value_int64, 0);
6967 if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
6968 grn_rset_recinfo_set_sum(ctx, ri, a->obj,
6969 GRN_INT64_VALUE(&value_int64));
6970 }
6971 GRN_OBJ_FIN(ctx, &value_int64);
6972 }
6973 }
6974 break;
6975 case GRN_ACCESSOR_GET_AVG :
6976 grn_obj_get_value(ctx, a->obj, id, &buf);
6977 {
6978 grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
6979 if (value->header.type == GRN_DB_FLOAT) {
6980 grn_rset_recinfo_set_avg(ctx, ri, a->obj, GRN_FLOAT_VALUE(value));
6981 } else {
6982 grn_obj value_float;
6983 GRN_FLOAT_INIT(&value_float, 0);
6984 if (!grn_obj_cast(ctx, value, &value_float, GRN_FALSE)) {
6985 grn_rset_recinfo_set_avg(ctx, ri, a->obj,
6986 GRN_FLOAT_VALUE(&value_float));
6987 }
6988 GRN_OBJ_FIN(ctx, &value_float);
6989 }
6990 }
6991 break;
6992 case GRN_ACCESSOR_GET_COLUMN_VALUE :
6993 /* todo : support vector */
6994 if (a->next) {
6995 grn_obj_get_value(ctx, a->obj, id, &buf);
6996 vp = GRN_BULK_HEAD(&buf);
6997 } else {
6998 rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
6999 }
7000 break;
7001 case GRN_ACCESSOR_LOOKUP :
7002 /* todo */
7003 break;
7004 case GRN_ACCESSOR_FUNCALL :
7005 /* todo */
7006 break;
7007 }
7008 if ((a = a->next)) {
7009 id = *((grn_id *)vp);
7010 } else {
7011 break;
7012 }
7013 }
7014 grn_obj_close(ctx, &buf);
7015 }
7016 return rc;
7017}
7018
7019#define INCRDECR(op) \
7020 switch (DB_OBJ(obj)->range) {\
7021 case GRN_DB_INT8 :\
7022 if (s == sizeof(int8_t)) {\
7023 int8_t *vp = (int8_t *)p;\
7024 *vp op *(int8_t *)v;\
7025 rc = GRN_SUCCESS;\
7026 } else {\
7027 rc = GRN_INVALID_ARGUMENT;\
7028 }\
7029 break;\
7030 case GRN_DB_UINT8 :\
7031 if (s == sizeof(uint8_t)) {\
7032 uint8_t *vp = (uint8_t *)p;\
7033 *vp op *(int8_t *)v;\
7034 rc = GRN_SUCCESS;\
7035 } else {\
7036 rc = GRN_INVALID_ARGUMENT;\
7037 }\
7038 break;\
7039 case GRN_DB_INT16 :\
7040 if (s == sizeof(int16_t)) {\
7041 int16_t *vp = (int16_t *)p;\
7042 *vp op *(int16_t *)v;\
7043 rc = GRN_SUCCESS;\
7044 } else {\
7045 rc = GRN_INVALID_ARGUMENT;\
7046 }\
7047 break;\
7048 case GRN_DB_UINT16 :\
7049 if (s == sizeof(uint16_t)) {\
7050 uint16_t *vp = (uint16_t *)p;\
7051 *vp op *(int16_t *)v;\
7052 rc = GRN_SUCCESS;\
7053 } else {\
7054 rc = GRN_INVALID_ARGUMENT;\
7055 }\
7056 break;\
7057 case GRN_DB_INT32 :\
7058 if (s == sizeof(int32_t)) {\
7059 int32_t *vp = (int32_t *)p;\
7060 *vp op *(int32_t *)v;\
7061 rc = GRN_SUCCESS;\
7062 } else {\
7063 rc = GRN_INVALID_ARGUMENT;\
7064 }\
7065 break;\
7066 case GRN_DB_UINT32 :\
7067 if (s == sizeof(uint32_t)) {\
7068 uint32_t *vp = (uint32_t *)p;\
7069 *vp op *(int32_t *)v;\
7070 rc = GRN_SUCCESS;\
7071 } else {\
7072 rc = GRN_INVALID_ARGUMENT;\
7073 }\
7074 break;\
7075 case GRN_DB_INT64 :\
7076 case GRN_DB_TIME :\
7077 if (s == sizeof(int64_t)) {\
7078 int64_t *vp = (int64_t *)p;\
7079 *vp op *(int64_t *)v;\
7080 rc = GRN_SUCCESS;\
7081 } else {\
7082 rc = GRN_INVALID_ARGUMENT;\
7083 }\
7084 break;\
7085 case GRN_DB_FLOAT :\
7086 if (s == sizeof(double)) {\
7087 double *vp = (double *)p;\
7088 *vp op *(double *)v;\
7089 rc = GRN_SUCCESS;\
7090 } else {\
7091 rc = GRN_INVALID_ARGUMENT;\
7092 }\
7093 break;\
7094 default :\
7095 rc = GRN_OPERATION_NOT_SUPPORTED;\
7096 break;\
7097 }
7098
7099uint32_t
7100grn_obj_size(grn_ctx *ctx, grn_obj *obj)
7101{
7102 if (!obj) { return 0; }
7103 switch (obj->header.type) {
7104 case GRN_VOID :
7105 case GRN_BULK :
7106 case GRN_PTR :
7107 case GRN_UVECTOR :
7108 case GRN_PVECTOR :
7109 case GRN_MSG :
7110 return GRN_BULK_VSIZE(obj);
7111 case GRN_VECTOR :
7112 return obj->u.v.body ? GRN_BULK_VSIZE(obj->u.v.body) : 0;
7113 default :
7114 return 0;
7115 }
7116}
7117
7118inline static int
7119call_hook(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value, int flags)
7120{
7121 grn_hook *hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET];
7122 void *v = GRN_BULK_HEAD(value);
7123 unsigned int s = grn_obj_size(ctx, value);
7124 if (hooks || obj->header.type == GRN_COLUMN_VAR_SIZE) {
7125 grn_obj oldbuf, *oldvalue;
7126 GRN_TEXT_INIT(&oldbuf, 0);
7127 oldvalue = grn_obj_get_value(ctx, obj, id, &oldbuf);
7128 if (flags & GRN_OBJ_SET) {
7129 void *ov;
7130 unsigned int os;
7131 ov = GRN_BULK_HEAD(oldvalue);
7132 os = grn_obj_size(ctx, oldvalue);
7133 if ((ov && v && os == s && !memcmp(ov, v, s)) &&
7134 !(obj->header.type == GRN_COLUMN_FIX_SIZE &&
7135 grn_bulk_is_zero(ctx, value))) {
7136 grn_obj_close(ctx, oldvalue);
7137 return 0;
7138 }
7139 }
7140 if (hooks) {
7141 // todo : grn_proc_ctx_open()
7142 grn_obj id_, flags_;
7143 grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4};
7144 GRN_UINT32_INIT(&id_, 0);
7145 GRN_UINT32_INIT(&flags_, 0);
7146 GRN_UINT32_SET(ctx, &id_, id);
7147 GRN_UINT32_SET(ctx, &flags_, flags);
7148 while (hooks) {
7149 grn_ctx_push(ctx, &id_);
7150 grn_ctx_push(ctx, oldvalue);
7151 grn_ctx_push(ctx, value);
7152 grn_ctx_push(ctx, &flags_);
7153 pctx.caller = NULL;
7154 pctx.currh = hooks;
7155 if (hooks->proc) {
7156 hooks->proc->funcs[PROC_INIT](ctx, 1, &obj, &pctx.user_data);
7157 } else {
7158 grn_obj_default_set_value_hook(ctx, 1, &obj, &pctx.user_data);
7159 }
7160 if (ctx->rc) {
7161 grn_obj_close(ctx, oldvalue);
7162 return 1;
7163 }
7164 hooks = hooks->next;
7165 pctx.offset++;
7166 }
7167 }
7168 grn_obj_close(ctx, oldvalue);
7169 }
7170 return 0;
7171}
7172
7173static grn_rc
7174grn_obj_set_value_table_pat_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
7175 grn_obj *value, int flags)
7176{
7177 grn_rc rc = GRN_INVALID_ARGUMENT;
7178 grn_id range = DB_OBJ(obj)->range;
7179 void *v = GRN_BULK_HEAD(value);
7180 grn_obj buf;
7181
7182 if (call_hook(ctx, obj, id, value, flags)) {
7183 if (ctx->rc) {
7184 rc = ctx->rc;
7185 }
7186 return rc;
7187 }
7188
7189 if (range != value->header.domain) {
7190 GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7191 if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7192 v = GRN_BULK_HEAD(&buf);
7193 }
7194 }
7195 rc = grn_pat_set_value(ctx, (grn_pat *)obj, id, v, flags);
7196 if (range != value->header.domain) {
7197 grn_obj_close(ctx, &buf);
7198 }
7199
7200 return rc;
7201}
7202
7203static grn_rc
7204grn_obj_set_value_table_hash_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
7205 grn_obj *value, int flags)
7206{
7207 grn_rc rc = GRN_INVALID_ARGUMENT;
7208 grn_id range = DB_OBJ(obj)->range;
7209 void *v = GRN_BULK_HEAD(value);
7210 grn_obj buf;
7211
7212 if (call_hook(ctx, obj, id, value, flags)) {
7213 if (ctx->rc) {
7214 rc = ctx->rc;
7215 }
7216 return rc;
7217 }
7218
7219 if (range != value->header.domain) {
7220 GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7221 if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7222 v = GRN_BULK_HEAD(&buf);
7223 }
7224 }
7225 rc = grn_hash_set_value(ctx, (grn_hash *)obj, id, v, flags);
7226 if (range != value->header.domain) {
7227 grn_obj_close(ctx, &buf);
7228 }
7229
7230 return rc;
7231}
7232
7233static grn_rc
7234grn_obj_set_value_table_no_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
7235 grn_obj *value, int flags)
7236{
7237 grn_rc rc = GRN_INVALID_ARGUMENT;
7238 grn_id range = DB_OBJ(obj)->range;
7239 void *v = GRN_BULK_HEAD(value);
7240 grn_obj buf;
7241
7242 if (call_hook(ctx, obj, id, value, flags)) {
7243 if (ctx->rc) {
7244 rc = ctx->rc;
7245 }
7246 return rc;
7247 }
7248
7249 if (range != value->header.domain) {
7250 GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7251 if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7252 v = GRN_BULK_HEAD(&buf);
7253 }
7254 }
7255 rc = grn_array_set_value(ctx, (grn_array *)obj, id, v, flags);
7256 if (range != value->header.domain) {
7257 grn_obj_close(ctx, &buf);
7258 }
7259
7260 return rc;
7261}
7262
7263static grn_rc
7264grn_obj_set_value_column_var_size_scalar(grn_ctx *ctx, grn_obj *obj, grn_id id,
7265 grn_obj *value, int flags)
7266{
7267 grn_rc rc = GRN_INVALID_ARGUMENT;
7268 grn_id range = DB_OBJ(obj)->range;
7269 void *v = GRN_BULK_HEAD(value);
7270 unsigned int s = grn_obj_size(ctx, value);
7271 grn_obj buf;
7272 grn_id buf_domain = GRN_DB_VOID;
7273
7274 if (call_hook(ctx, obj, id, value, flags)) {
7275 if (ctx->rc) {
7276 rc = ctx->rc;
7277 }
7278 return rc;
7279 }
7280
7281 switch (flags & GRN_OBJ_SET_MASK) {
7282 case GRN_OBJ_INCR :
7283 case GRN_OBJ_DECR :
7284 if (value->header.domain == GRN_DB_INT32 ||
7285 value->header.domain == GRN_DB_INT64) {
7286 /* do nothing */
7287 } else if (GRN_DB_INT8 <= value->header.domain &&
7288 value->header.domain < GRN_DB_INT32) {
7289 buf_domain = GRN_DB_INT32;
7290 } else {
7291 buf_domain = GRN_DB_INT64;
7292 }
7293 break;
7294 default :
7295 if (range != value->header.domain) {
7296 buf_domain = range;
7297 }
7298 break;
7299 }
7300
7301 if (buf_domain != GRN_DB_VOID) {
7302 GRN_OBJ_INIT(&buf, GRN_BULK, 0, buf_domain);
7303 if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
7304 v = GRN_BULK_HEAD(&buf);
7305 s = GRN_BULK_VSIZE(&buf);
7306 }
7307 }
7308
7309 rc = grn_ja_put(ctx, (grn_ja *)obj, id, v, s, flags, NULL);
7310
7311 if (buf_domain != GRN_DB_VOID) {
7312 grn_obj_close(ctx, &buf);
7313 }
7314
7315 return rc;
7316}
7317
7318static grn_rc
7319grn_obj_set_value_column_var_size_vector_uvector(grn_ctx *ctx, grn_obj *column,
7320 grn_id id, grn_obj *value,
7321 int flags)
7322{
7323 grn_rc rc = GRN_SUCCESS;
7324 grn_obj uvector;
7325 grn_obj_flags uvector_flags = 0;
7326 grn_bool need_convert = GRN_FALSE;
7327 grn_bool need_cast = GRN_FALSE;
7328 grn_id column_range_id;
7329 void *raw_value;
7330 unsigned int size;
7331
7332 if (column->header.flags & GRN_OBJ_WITH_WEIGHT) {
7333 if (!IS_WEIGHT_UVECTOR(value)) {
7334 need_convert = GRN_TRUE;
7335 }
7336 } else {
7337 if (IS_WEIGHT_UVECTOR(value)) {
7338 need_convert = GRN_TRUE;
7339 uvector_flags = GRN_OBJ_WITH_WEIGHT;
7340 }
7341 }
7342 column_range_id = DB_OBJ(column)->range;
7343 if (column_range_id != value->header.domain) {
7344 need_convert = GRN_TRUE;
7345 need_cast = GRN_TRUE;
7346 }
7347
7348 if (need_convert) {
7349 unsigned int i, n;
7350
7351 GRN_VALUE_FIX_SIZE_INIT(&uvector, GRN_OBJ_VECTOR, column_range_id);
7352 uvector.header.flags |= uvector_flags;
7353 n = grn_uvector_size(ctx, value);
7354 if (need_cast) {
7355 grn_obj value_record;
7356 grn_obj casted_record;
7357
7358 GRN_VALUE_FIX_SIZE_INIT(&value_record, 0, value->header.domain);
7359 GRN_VALUE_FIX_SIZE_INIT(&casted_record, 0, column_range_id);
7360 for (i = 0; i < n; i++) {
7361 grn_id id;
7362 grn_id casted_id;
7363 unsigned int weight = 0;
7364
7365 GRN_BULK_REWIND(&value_record);
7366 GRN_BULK_REWIND(&casted_record);
7367
7368 id = grn_uvector_get_element(ctx, value, i, NULL);
7369 GRN_RECORD_SET(ctx, &value_record, id);
7370 rc = grn_obj_cast(ctx, &value_record, &casted_record, GRN_TRUE);
7371 if (rc != GRN_SUCCESS) {
7372 char column_name[GRN_TABLE_MAX_KEY_SIZE];
7373 int column_name_size;
7374 grn_obj inspected;
7375 column_name_size = grn_obj_name(ctx,
7376 column,
7377 column_name,
7378 GRN_TABLE_MAX_KEY_SIZE);
7379 GRN_TEXT_INIT(&inspected, 0);
7380 grn_inspect(ctx, &inspected, &value_record);
7381 ERR(rc,
7382 "[column][set-value] failed to cast: <%.*s>: <%.*s>",
7383 column_name_size,
7384 column_name,
7385 (int)GRN_TEXT_LEN(&inspected),
7386 GRN_TEXT_VALUE(&inspected));
7387 GRN_OBJ_FIN(ctx, &inspected);
7388 break;
7389 }
7390 casted_id = GRN_RECORD_VALUE(&casted_record);
7391 grn_uvector_add_element(ctx, &uvector, casted_id, weight);
7392 }
7393
7394 GRN_OBJ_FIN(ctx, &value_record);
7395 GRN_OBJ_FIN(ctx, &casted_record);
7396 } else {
7397 for (i = 0; i < n; i++) {
7398 grn_id id;
7399 unsigned int weight = 0;
7400 id = grn_uvector_get_element(ctx, value, i, NULL);
7401 grn_uvector_add_element(ctx, &uvector, id, weight);
7402 }
7403 }
7404 raw_value = GRN_BULK_HEAD(&uvector);
7405 size = GRN_BULK_VSIZE(&uvector);
7406 } else {
7407 raw_value = GRN_BULK_HEAD(value);
7408 size = GRN_BULK_VSIZE(value);
7409 }
7410
7411 if (rc == GRN_SUCCESS) {
7412 rc = grn_ja_put(ctx, (grn_ja *)column, id, raw_value, size, flags, NULL);
7413 }
7414
7415 if (need_convert) {
7416 GRN_OBJ_FIN(ctx, &uvector);
7417 }
7418
7419 return rc;
7420}
7421
7422static grn_rc
7423grn_obj_set_value_column_var_size_vector(grn_ctx *ctx, grn_obj *obj, grn_id id,
7424 grn_obj *value, int flags)
7425{
7426 grn_rc rc = GRN_INVALID_ARGUMENT;
7427 grn_id range = DB_OBJ(obj)->range;
7428 void *v = GRN_BULK_HEAD(value);
7429 unsigned int s = grn_obj_size(ctx, value);
7430 grn_obj *lexicon = grn_ctx_at(ctx, range);
7431
7432 if (call_hook(ctx, obj, id, value, flags)) {
7433 if (ctx->rc) {
7434 rc = ctx->rc;
7435 }
7436 return rc;
7437 }
7438
7439 if (value->header.type == GRN_UVECTOR) {
7440 rc = grn_obj_set_value_column_var_size_vector_uvector(ctx, obj,
7441 id, value,
7442 flags);
7443 return rc;
7444 }
7445
7446 if (GRN_OBJ_TABLEP(lexicon)) {
7447 grn_obj uvector;
7448 GRN_RECORD_INIT(&uvector, GRN_OBJ_VECTOR, range);
7449 if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
7450 uvector.header.flags |= GRN_OBJ_WITH_WEIGHT;
7451 }
7452 switch (value->header.type) {
7453 case GRN_BULK :
7454 {
7455 unsigned int token_flags = 0;
7456 grn_token_cursor *token_cursor;
7457 if (v && s &&
7458 (token_cursor = grn_token_cursor_open(ctx, lexicon, v, s,
7459 GRN_TOKEN_ADD, token_flags))) {
7460 while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
7461 grn_id tid = grn_token_cursor_next(ctx, token_cursor);
7462 grn_uvector_add_element(ctx, &uvector, tid, 0);
7463 }
7464 grn_token_cursor_close(ctx, token_cursor);
7465 }
7466 rc = grn_ja_put(ctx, (grn_ja *)obj, id,
7467 GRN_BULK_HEAD(&uvector), GRN_BULK_VSIZE(&uvector),
7468 flags, NULL);
7469 }
7470 break;
7471 case GRN_VECTOR :
7472 {
7473 unsigned int n;
7474 n = grn_vector_size(ctx, value);
7475 if (n > 0) {
7476 unsigned int i;
7477 grn_obj value_buf, cast_buf;
7478 GRN_OBJ_INIT(&value_buf, GRN_BULK, 0, GRN_DB_VOID);
7479 GRN_OBJ_INIT(&cast_buf, GRN_BULK, 0, lexicon->header.domain);
7480 for (i = 0; i < n; i++) {
7481 grn_id tid;
7482 const char *element;
7483 unsigned int element_length;
7484 unsigned int weight;
7485 grn_id element_domain;
7486
7487 element_length = grn_vector_get_element(ctx, value, i,
7488 &element, &weight,
7489 &element_domain);
7490 if (element_domain != lexicon->header.domain) {
7491 GRN_BULK_REWIND(&cast_buf);
7492 GRN_BULK_REWIND(&value_buf);
7493 grn_bulk_write(ctx, &value_buf, element, element_length);
7494 value_buf.header.domain = element_domain;
7495 rc = grn_obj_cast(ctx, &value_buf, &cast_buf, GRN_TRUE);
7496 if (rc) {
7497 grn_obj *range_obj;
7498 range_obj = grn_ctx_at(ctx, range);
7499 ERR_CAST(obj, range_obj, &value_buf);
7500 grn_obj_unlink(ctx, range_obj);
7501 } else {
7502 element = GRN_BULK_HEAD(&cast_buf);
7503 element_length = GRN_BULK_VSIZE(&cast_buf);
7504 }
7505 } else {
7506 rc = GRN_SUCCESS;
7507 }
7508 if (rc) {
7509 continue;
7510 }
7511 tid = grn_table_add(ctx, lexicon, element, element_length, NULL);
7512 grn_uvector_add_element(ctx, &uvector, tid, weight);
7513 }
7514 GRN_OBJ_FIN(ctx, &value_buf);
7515 GRN_OBJ_FIN(ctx, &cast_buf);
7516 }
7517 }
7518 rc = grn_ja_put(ctx, (grn_ja *)obj, id,
7519 GRN_BULK_HEAD(&uvector), GRN_BULK_VSIZE(&uvector),
7520 flags, NULL);
7521 break;
7522 default :
7523 ERR(GRN_INVALID_ARGUMENT, "vector, uvector or bulk required");
7524 break;
7525 }
7526 grn_obj_close(ctx, &uvector);
7527 } else {
7528 switch (value->header.type) {
7529 case GRN_BULK :
7530 if (!GRN_BULK_VSIZE(value)) {
7531 rc = grn_ja_put(ctx, (grn_ja *)obj, id, NULL, 0, flags, NULL);
7532 } else {
7533 grn_obj v;
7534 GRN_OBJ_INIT(&v, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, GRN_DB_TEXT);
7535 v.u.v.body = value;
7536 grn_vector_delimit(ctx, &v, 0, GRN_ID_NIL);
7537 rc = grn_ja_putv(ctx, (grn_ja *)obj, id, &v, 0);
7538 grn_obj_close(ctx, &v);
7539 }
7540 break;
7541 case GRN_VECTOR :
7542 rc = grn_ja_putv(ctx, (grn_ja *)obj, id, value, 0);
7543 break;
7544 default :
7545 ERR(GRN_INVALID_ARGUMENT, "vector or bulk required");
7546 break;
7547 }
7548 }
7549 return rc;
7550}
7551
7552static grn_rc
7553grn_obj_set_value_column_fix_size(grn_ctx *ctx, grn_obj *obj, grn_id id,
7554 grn_obj *value, int flags)
7555{
7556 grn_rc rc = GRN_INVALID_ARGUMENT;
7557 grn_id range = DB_OBJ(obj)->range;
7558 void *v = GRN_BULK_HEAD(value);
7559 unsigned int s = grn_obj_size(ctx, value);
7560 grn_obj buf, *value_ = value;
7561 uint32_t element_size = ((grn_ra *)obj)->header->element_size;
7562 GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
7563 if (range != value->header.domain) {
7564 rc = grn_obj_cast(ctx, value, &buf, GRN_TRUE);
7565 if (rc) {
7566 grn_obj *range_obj;
7567 range_obj = grn_ctx_at(ctx, range);
7568 ERR_CAST(obj, range_obj, value);
7569 grn_obj_unlink(ctx, range_obj);
7570 } else {
7571 value_ = &buf;
7572 v = GRN_BULK_HEAD(&buf);
7573 s = GRN_BULK_VSIZE(&buf);
7574 }
7575 } else {
7576 rc = GRN_SUCCESS;
7577 }
7578 if (rc) {
7579 /* do nothing because it already has error. */
7580 } else if (element_size < s) {
7581 ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", s);
7582 } else {
7583 void *p = grn_ra_ref(ctx, (grn_ra *)obj, id);
7584 if (!p) {
7585 ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
7586 rc = GRN_NO_MEMORY_AVAILABLE;
7587 return rc;
7588 }
7589 switch (flags & GRN_OBJ_SET_MASK) {
7590 case GRN_OBJ_SET :
7591 if (call_hook(ctx, obj, id, value_, flags)) {
7592 if (ctx->rc) {
7593 rc = ctx->rc;
7594 }
7595 GRN_OBJ_FIN(ctx, &buf);
7596 grn_ra_unref(ctx, (grn_ra *)obj, id);
7597 return rc;
7598 }
7599 if (element_size != s) {
7600 if (!s) {
7601 memset(p, 0, element_size);
7602 } else {
7603 void *b;
7604 if ((b = GRN_CALLOC(element_size))) {
7605 grn_memcpy(b, v, s);
7606 grn_memcpy(p, b, element_size);
7607 GRN_FREE(b);
7608 }
7609 }
7610 } else {
7611 grn_memcpy(p, v, s);
7612 }
7613 rc = GRN_SUCCESS;
7614 break;
7615 case GRN_OBJ_INCR :
7616 /* todo : support hook */
7617 INCRDECR(+=);
7618 break;
7619 case GRN_OBJ_DECR :
7620 /* todo : support hook */
7621 INCRDECR(-=);
7622 break;
7623 default :
7624 rc = GRN_OPERATION_NOT_SUPPORTED;
7625 break;
7626 }
7627 grn_ra_unref(ctx, (grn_ra *)obj, id);
7628 }
7629 GRN_OBJ_FIN(ctx, &buf);
7630 return rc;
7631}
7632
7633static grn_rc
7634grn_obj_set_value_column_index(grn_ctx *ctx, grn_obj *obj, grn_id id,
7635 grn_obj *value, int flags)
7636{
7637 char column_name[GRN_TABLE_MAX_KEY_SIZE];
7638 int column_name_size;
7639 column_name_size = grn_obj_name(ctx, obj, column_name,
7640 GRN_TABLE_MAX_KEY_SIZE);
7641 ERR(GRN_INVALID_ARGUMENT,
7642 "can't set value to index column directly: <%.*s>",
7643 column_name_size, column_name);
7644 return ctx->rc;
7645}
7646
7647grn_rc
7648grn_obj_set_value(grn_ctx *ctx, grn_obj *obj, grn_id id,
7649 grn_obj *value, int flags)
7650{
7651 grn_rc rc = GRN_INVALID_ARGUMENT;
7652 GRN_API_ENTER;
7653 if (!GRN_DB_OBJP(obj)) {
7654 if (obj->header.type == GRN_ACCESSOR) {
7655 rc = grn_accessor_set_value(ctx, (grn_accessor *)obj, id, value, flags);
7656 } else {
7657 ERR(GRN_INVALID_ARGUMENT, "not db_obj");
7658 }
7659 } else {
7660 switch (obj->header.type) {
7661 case GRN_TABLE_PAT_KEY :
7662 rc = grn_obj_set_value_table_pat_key(ctx, obj, id, value, flags);
7663 break;
7664 case GRN_TABLE_DAT_KEY :
7665 rc = GRN_OPERATION_NOT_SUPPORTED;
7666 break;
7667 case GRN_TABLE_HASH_KEY :
7668 rc = grn_obj_set_value_table_hash_key(ctx, obj, id, value, flags);
7669 break;
7670 case GRN_TABLE_NO_KEY :
7671 rc = grn_obj_set_value_table_no_key(ctx, obj, id, value, flags);
7672 break;
7673 case GRN_COLUMN_VAR_SIZE :
7674 switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
7675 case GRN_OBJ_COLUMN_SCALAR :
7676 rc = grn_obj_set_value_column_var_size_scalar(ctx, obj, id, value,
7677 flags);
7678 break;
7679 case GRN_OBJ_COLUMN_VECTOR :
7680 rc = grn_obj_set_value_column_var_size_vector(ctx, obj, id, value,
7681 flags);
7682 break;
7683 default :
7684 ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
7685 break;
7686 }
7687 break;
7688 case GRN_COLUMN_FIX_SIZE :
7689 rc = grn_obj_set_value_column_fix_size(ctx, obj, id, value, flags);
7690 break;
7691 case GRN_COLUMN_INDEX :
7692 rc = grn_obj_set_value_column_index(ctx, obj, id, value, flags);
7693 break;
7694 }
7695 }
7696 GRN_API_RETURN(rc);
7697}
7698
7699const char *
7700grn_obj_get_value_(grn_ctx *ctx, grn_obj *obj, grn_id id, uint32_t *size)
7701{
7702 const char *value = NULL;
7703 *size = 0;
7704 switch (obj->header.type) {
7705 case GRN_ACCESSOR :
7706 value = grn_accessor_get_value_(ctx, (grn_accessor *)obj, id, size);
7707 break;
7708 case GRN_TABLE_PAT_KEY :
7709 value = grn_pat_get_value_(ctx, (grn_pat *)obj, id, size);
7710 break;
7711 case GRN_TABLE_DAT_KEY :
7712 ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
7713 break;
7714 case GRN_TABLE_HASH_KEY :
7715 value = grn_hash_get_value_(ctx, (grn_hash *)obj, id, size);
7716 break;
7717 case GRN_TABLE_NO_KEY :
7718 if ((value = _grn_array_get_value(ctx, (grn_array *)obj, id))) {
7719 *size = ((grn_array *)obj)->value_size;
7720 }
7721 break;
7722 case GRN_COLUMN_VAR_SIZE :
7723 {
7724 grn_io_win jw;
7725 if ((value = grn_ja_ref(ctx, (grn_ja *)obj, id, &jw, size))) {
7726 grn_ja_unref(ctx, &jw);
7727 }
7728 }
7729 break;
7730 case GRN_COLUMN_FIX_SIZE :
7731 if ((value = grn_ra_ref(ctx, (grn_ra *)obj, id))) {
7732 grn_ra_unref(ctx, (grn_ra *)obj, id);
7733 *size = ((grn_ra *)obj)->header->element_size;
7734 }
7735 break;
7736 case GRN_COLUMN_INDEX :
7737 ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "todo: GRN_COLUMN_INDEX");
7738 break;
7739 }
7740 return value;
7741}
7742
7743static void
7744grn_obj_get_value_expr(grn_ctx *ctx, grn_obj *expr, grn_id id, grn_obj *value)
7745{
7746 grn_expr *e = (grn_expr *)expr;
7747 grn_expr_code *code;
7748
7749 if (e->codes_curr != 1) {
7750 return;
7751 }
7752
7753 code = e->codes;
7754 if (code->op != GRN_OP_GET_VALUE) {
7755 return;
7756 }
7757
7758 if (!code->value) {
7759 return;
7760 }
7761
7762 switch (code->value->header.type) {
7763 case GRN_COLUMN_VAR_SIZE :
7764 case GRN_COLUMN_FIX_SIZE :
7765 grn_obj_get_value(ctx, code->value, id, value);
7766 break;
7767 default :
7768 break;
7769 }
7770}
7771
7772static void
7773grn_obj_get_value_column_index(grn_ctx *ctx, grn_obj *index_column,
7774 grn_id id, grn_obj *value)
7775{
7776 grn_ii *ii = (grn_ii *)index_column;
7777 grn_obj_ensure_bulk(ctx, value);
7778 if (id) {
7779 GRN_UINT32_SET(ctx, value, grn_ii_estimate_size(ctx, ii, id));
7780 } else {
7781 GRN_UINT32_SET(ctx, value, 0);
7782 }
7783 value->header.domain = GRN_DB_UINT32;
7784}
7785
7786static grn_obj *
7787grn_obj_get_value_column_vector(grn_ctx *ctx, grn_obj *obj,
7788 grn_id id, grn_obj *value)
7789{
7790 grn_obj *lexicon;
7791
7792 lexicon = grn_ctx_at(ctx, DB_OBJ(obj)->range);
7793 if (lexicon && !GRN_OBJ_TABLEP(lexicon) &&
7794 (lexicon->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
7795 grn_obj_ensure_vector(ctx, value);
7796 if (id) {
7797 grn_obj v_;
7798 GRN_TEXT_INIT(&v_, 0);
7799 grn_ja_get_value(ctx, (grn_ja *)obj, id, &v_);
7800 grn_vector_decode(ctx, value, GRN_TEXT_VALUE(&v_), GRN_TEXT_LEN(&v_));
7801 GRN_OBJ_FIN(ctx, &v_);
7802 }
7803 } else {
7804 grn_obj_ensure_bulk(ctx, value);
7805 if (id) {
7806 grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
7807 }
7808 value->header.type = GRN_UVECTOR;
7809 if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
7810 value->header.flags |= GRN_OBJ_WITH_WEIGHT;
7811 } else {
7812 value->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
7813 }
7814 }
7815
7816 return value;
7817}
7818
7819grn_obj *
7820grn_obj_get_value(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value)
7821{
7822 GRN_API_ENTER;
7823 if (!obj) {
7824 ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
7825 goto exit;
7826 }
7827 if (!value) {
7828 if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
7829 ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
7830 goto exit;
7831 }
7832 }
7833 switch (value->header.type) {
7834 case GRN_VOID :
7835 grn_obj_reinit(ctx, value, GRN_DB_TEXT, 0);
7836 break;
7837 case GRN_BULK :
7838 case GRN_VECTOR :
7839 case GRN_UVECTOR :
7840 case GRN_MSG :
7841 break;
7842 default :
7843 ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
7844 goto exit;
7845 }
7846 switch (obj->header.type) {
7847 case GRN_ACCESSOR :
7848 grn_obj_ensure_bulk(ctx, value);
7849 value = grn_accessor_get_value(ctx, (grn_accessor *)obj, id, value);
7850 break;
7851 case GRN_EXPR :
7852 grn_obj_get_value_expr(ctx, obj, id, value);
7853 break;
7854 case GRN_TABLE_PAT_KEY :
7855 {
7856 grn_pat *pat = (grn_pat *)obj;
7857 uint32_t size = pat->value_size;
7858 grn_obj_ensure_bulk(ctx, value);
7859 if (id) {
7860 if (grn_bulk_space(ctx, value, size)) {
7861 MERR("grn_bulk_space failed");
7862 goto exit;
7863 }
7864 {
7865 char *curr = GRN_BULK_CURR(value);
7866 grn_pat_get_value(ctx, pat, id, curr - size);
7867 }
7868 }
7869 value->header.type = GRN_BULK;
7870 value->header.domain = grn_obj_get_range(ctx, obj);
7871 }
7872 break;
7873 case GRN_TABLE_DAT_KEY :
7874 ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
7875 break;
7876 case GRN_TABLE_HASH_KEY :
7877 {
7878 grn_bool processed = GRN_FALSE;
7879 grn_obj_ensure_bulk(ctx, value);
7880 value->header.domain = grn_obj_get_range(ctx, obj);
7881 if (id) {
7882 if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(obj)) {
7883 grn_obj *domain;
7884 domain = grn_ctx_at(ctx, value->header.domain);
7885 if (GRN_OBJ_TABLEP(domain)) {
7886 grn_id subrec_id;
7887 if (grn_table_get_subrecs(ctx, obj, id, &subrec_id, NULL, 1) == 1) {
7888 GRN_RECORD_SET(ctx, value, subrec_id);
7889 processed = GRN_TRUE;
7890 }
7891 }
7892 }
7893 if (!processed) {
7894 grn_hash *hash = (grn_hash *)obj;
7895 uint32_t size = hash->value_size;
7896 if (grn_bulk_space(ctx, value, size)) {
7897 MERR("grn_bulk_space failed");
7898 goto exit;
7899 }
7900 {
7901 char *curr = GRN_BULK_CURR(value);
7902 grn_hash_get_value(ctx, hash, id, curr - size);
7903 }
7904 }
7905 }
7906 }
7907 break;
7908 case GRN_TABLE_NO_KEY :
7909 {
7910 grn_array *array = (grn_array *)obj;
7911 uint32_t size = array->value_size;
7912 grn_obj_ensure_bulk(ctx, value);
7913 if (id) {
7914 if (grn_bulk_space(ctx, value, size)) {
7915 MERR("grn_bulk_space failed");
7916 goto exit;
7917 }
7918 {
7919 char *curr = GRN_BULK_CURR(value);
7920 grn_array_get_value(ctx, array, id, curr - size);
7921 }
7922 }
7923 value->header.type = GRN_BULK;
7924 value->header.domain = grn_obj_get_range(ctx, obj);
7925 }
7926 break;
7927 case GRN_COLUMN_VAR_SIZE :
7928 switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
7929 case GRN_OBJ_COLUMN_VECTOR :
7930 grn_obj_get_value_column_vector(ctx, obj, id, value);
7931 break;
7932 case GRN_OBJ_COLUMN_SCALAR :
7933 grn_obj_ensure_bulk(ctx, value);
7934 if (id) {
7935 grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
7936 }
7937 value->header.type = GRN_BULK;
7938 break;
7939 default :
7940 ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
7941 break;
7942 }
7943 value->header.domain = grn_obj_get_range(ctx, obj);
7944 break;
7945 case GRN_COLUMN_FIX_SIZE :
7946 grn_obj_ensure_bulk(ctx, value);
7947 value->header.type = GRN_BULK;
7948 value->header.domain = grn_obj_get_range(ctx, obj);
7949 if (id) {
7950 unsigned int element_size;
7951 void *v = grn_ra_ref(ctx, (grn_ra *)obj, id);
7952 if (v) {
7953 element_size = ((grn_ra *)obj)->header->element_size;
7954 grn_bulk_write(ctx, value, v, element_size);
7955 grn_ra_unref(ctx, (grn_ra *)obj, id);
7956 }
7957 }
7958 break;
7959 case GRN_COLUMN_INDEX :
7960 grn_obj_get_value_column_index(ctx, obj, id, value);
7961 break;
7962 }
7963exit :
7964 GRN_API_RETURN(value);
7965}
7966
7967int
7968grn_obj_get_values(grn_ctx *ctx, grn_obj *obj, grn_id offset, void **values)
7969{
7970 int nrecords = -1;
7971 GRN_API_ENTER;
7972 if (obj->header.type == GRN_COLUMN_FIX_SIZE) {
7973 grn_obj *domain = grn_column_table(ctx, obj);
7974 if (domain) {
7975 int table_size = (int)grn_table_size(ctx, domain);
7976 if (0 < offset && offset <= table_size) {
7977 grn_ra *ra = (grn_ra *)obj;
7978 void *p = grn_ra_ref(ctx, ra, offset);
7979 if (p) {
7980 if ((offset >> ra->element_width) == (table_size >> ra->element_width)) {
7981 nrecords = (table_size & ra->element_mask) + 1 - (offset & ra->element_mask);
7982 } else {
7983 nrecords = ra->element_mask + 1 - (offset & ra->element_mask);
7984 }
7985 if (values) { *values = p; }
7986 grn_ra_unref(ctx, ra, offset);
7987 } else {
7988 ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
7989 }
7990 } else {
7991 nrecords = 0;
7992 }
7993 } else {
7994 ERR(GRN_INVALID_ARGUMENT, "no domain found");
7995 }
7996 } else {
7997 ERR(GRN_INVALID_ARGUMENT, "obj is not a fix sized column");
7998 }
7999 GRN_API_RETURN(nrecords);
8000}
8001
8002grn_rc
8003grn_column_index_update(grn_ctx *ctx, grn_obj *column,
8004 grn_id id, unsigned int section,
8005 grn_obj *oldvalue, grn_obj *newvalue)
8006{
8007 grn_rc rc = GRN_INVALID_ARGUMENT;
8008 GRN_API_ENTER;
8009 if (column->header.type != GRN_COLUMN_INDEX) {
8010 ERR(GRN_INVALID_ARGUMENT, "invalid column assigned");
8011 } else {
8012 rc = grn_ii_column_update(ctx, (grn_ii *)column, id, section, oldvalue, newvalue, NULL);
8013 }
8014 GRN_API_RETURN(rc);
8015}
8016
8017grn_obj *
8018grn_column_table(grn_ctx *ctx, grn_obj *column)
8019{
8020 grn_obj *obj = NULL;
8021 grn_db_obj *col = DB_OBJ(column);
8022 GRN_API_ENTER;
8023 if (col) {
8024 obj = grn_ctx_at(ctx, col->header.domain);
8025 }
8026 GRN_API_RETURN(obj);
8027}
8028
8029grn_obj *
8030grn_obj_get_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *valuebuf)
8031{
8032 GRN_API_ENTER;
8033 switch (type) {
8034 case GRN_INFO_SUPPORT_ZLIB :
8035 if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8036 ERR(GRN_INVALID_ARGUMENT,
8037 "failed to open value buffer for GRN_INFO_ZLIB_SUPPORT");
8038 goto exit;
8039 }
8040#ifdef GRN_WITH_ZLIB
8041 GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8042#else
8043 GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8044#endif
8045 break;
8046 case GRN_INFO_SUPPORT_LZ4 :
8047 if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8048 ERR(GRN_INVALID_ARGUMENT,
8049 "failed to open value buffer for GRN_INFO_LZ4_SUPPORT");
8050 goto exit;
8051 }
8052#ifdef GRN_WITH_LZ4
8053 GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8054#else /* GRN_WITH_LZ4 */
8055 GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8056#endif /* GRN_WITH_LZ4 */
8057 break;
8058 case GRN_INFO_SUPPORT_ZSTD :
8059 if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8060 ERR(GRN_INVALID_ARGUMENT,
8061 "failed to open value buffer for GRN_INFO_ZSTD_SUPPORT");
8062 goto exit;
8063 }
8064#ifdef GRN_WITH_ZSTD
8065 GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8066#else /* GRN_WITH_ZSTD */
8067 GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8068#endif /* GRN_WITH_ZSTD */
8069 break;
8070 case GRN_INFO_SUPPORT_ARROW :
8071 if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
8072 ERR(GRN_INVALID_ARGUMENT,
8073 "failed to open value buffer for GRN_INFO_ARROW_SUPPORT");
8074 goto exit;
8075 }
8076#ifdef GRN_WITH_ARROW
8077 GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
8078#else /* GRN_WITH_ARROW */
8079 GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
8080#endif /* GRN_WITH_ARROW */
8081 break;
8082 default :
8083 if (!obj) {
8084 ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8085 goto exit;
8086 }
8087 switch (type) {
8088 case GRN_INFO_ENCODING :
8089 if (!valuebuf) {
8090 if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
8091 ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8092 goto exit;
8093 }
8094 }
8095 {
8096 grn_encoding enc;
8097 if (obj->header.type == GRN_DB) { obj = ((grn_db *)obj)->keys; }
8098 switch (obj->header.type) {
8099 case GRN_TABLE_PAT_KEY :
8100 enc = ((grn_pat *)obj)->encoding;
8101 grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
8102 break;
8103 case GRN_TABLE_DAT_KEY :
8104 enc = ((grn_dat *)obj)->encoding;
8105 grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
8106 break;
8107 case GRN_TABLE_HASH_KEY :
8108 enc = ((grn_hash *)obj)->encoding;
8109 grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
8110 break;
8111 default :
8112 ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8113 }
8114 }
8115 break;
8116 case GRN_INFO_SOURCE :
8117 if (!valuebuf) {
8118 if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
8119 ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
8120 goto exit;
8121 }
8122 }
8123 if (!GRN_DB_OBJP(obj)) {
8124 ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
8125 goto exit;
8126 }
8127 grn_bulk_write(ctx, valuebuf, DB_OBJ(obj)->source, DB_OBJ(obj)->source_size);
8128 break;
8129 case GRN_INFO_DEFAULT_TOKENIZER :
8130 switch (DB_OBJ(obj)->header.type) {
8131 case GRN_TABLE_HASH_KEY :
8132 valuebuf = ((grn_hash *)obj)->tokenizer;
8133 break;
8134 case GRN_TABLE_PAT_KEY :
8135 valuebuf = ((grn_pat *)obj)->tokenizer;
8136 break;
8137 case GRN_TABLE_DAT_KEY :
8138 valuebuf = ((grn_dat *)obj)->tokenizer;
8139 break;
8140 }
8141 break;
8142 case GRN_INFO_NORMALIZER :
8143 switch (DB_OBJ(obj)->header.type) {
8144 case GRN_TABLE_HASH_KEY :
8145 valuebuf = ((grn_hash *)obj)->normalizer;
8146 break;
8147 case GRN_TABLE_PAT_KEY :
8148 valuebuf = ((grn_pat *)obj)->normalizer;
8149 break;
8150 case GRN_TABLE_DAT_KEY :
8151 valuebuf = ((grn_dat *)obj)->normalizer;
8152 break;
8153 }
8154 break;
8155 case GRN_INFO_TOKEN_FILTERS :
8156 if (!valuebuf) {
8157 if (!(valuebuf = grn_obj_open(ctx, GRN_PVECTOR, 0, 0))) {
8158 ERR(GRN_NO_MEMORY_AVAILABLE,
8159 "grn_obj_get_info: failed to allocate value buffer");
8160 goto exit;
8161 }
8162 }
8163 {
8164 grn_obj *token_filters = NULL;
8165 switch (obj->header.type) {
8166 case GRN_TABLE_HASH_KEY :
8167 token_filters = &(((grn_hash *)obj)->token_filters);
8168 break;
8169 case GRN_TABLE_PAT_KEY :
8170 token_filters = &(((grn_pat *)obj)->token_filters);
8171 break;
8172 case GRN_TABLE_DAT_KEY :
8173 token_filters = &(((grn_dat *)obj)->token_filters);
8174 break;
8175 default :
8176 ERR(GRN_INVALID_ARGUMENT,
8177 /* TODO: Show type name instead of type ID */
8178 "[info][get][token-filters] target object must be one of "
8179 "GRN_TABLE_HASH_KEY, GRN_TABLE_PAT_KEY and GRN_TABLE_DAT_KEY: %d",
8180 obj->header.type);
8181 break;
8182 }
8183 if (token_filters) {
8184 grn_bulk_write(ctx,
8185 valuebuf,
8186 GRN_BULK_HEAD(token_filters),
8187 GRN_BULK_VSIZE(token_filters));
8188 }
8189 }
8190 break;
8191 default :
8192 /* todo */
8193 break;
8194 }
8195 }
8196exit :
8197 GRN_API_RETURN(valuebuf);
8198}
8199
8200static void
8201update_source_hook(grn_ctx *ctx, grn_obj *obj)
8202{
8203 grn_id *s = DB_OBJ(obj)->source;
8204 int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
8205 grn_obj_default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
8206 grn_obj *source, data;
8207 GRN_TEXT_INIT(&data, GRN_OBJ_DO_SHALLOW_COPY);
8208 GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
8209 for (i = 1; i <= n; i++, s++) {
8210 hook_data.section = i;
8211 if ((source = grn_ctx_at(ctx, *s))) {
8212 switch (source->header.type) {
8213 case GRN_TABLE_HASH_KEY :
8214 case GRN_TABLE_PAT_KEY :
8215 case GRN_TABLE_DAT_KEY :
8216 grn_obj_add_hook(ctx, source, GRN_HOOK_INSERT, 0, NULL, &data);
8217 grn_obj_add_hook(ctx, source, GRN_HOOK_DELETE, 0, NULL, &data);
8218 break;
8219 case GRN_COLUMN_FIX_SIZE :
8220 case GRN_COLUMN_VAR_SIZE :
8221 case GRN_COLUMN_INDEX :
8222 grn_obj_add_hook(ctx, source, GRN_HOOK_SET, 0, NULL, &data);
8223 break;
8224 default :
8225 /* invalid target */
8226 break;
8227 }
8228 }
8229 }
8230 grn_obj_close(ctx, &data);
8231}
8232
8233static void
8234del_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, grn_obj *hld)
8235{
8236 int i;
8237 void *hld_value = NULL;
8238 uint32_t hld_size = 0;
8239 grn_hook **last;
8240 hld_value = GRN_BULK_HEAD(hld);
8241 hld_size = GRN_BULK_VSIZE(hld);
8242 if (!hld_size) { return; }
8243 for (i = 0, last = &DB_OBJ(obj)->hooks[entry]; *last; i++, last = &(*last)->next) {
8244 if (!memcmp(GRN_NEXT_ADDR(*last), hld_value, hld_size)) {
8245 grn_obj_delete_hook(ctx, obj, entry, i);
8246 return;
8247 }
8248 }
8249}
8250
8251static void
8252delete_source_hook(grn_ctx *ctx, grn_obj *obj)
8253{
8254 grn_id *s = DB_OBJ(obj)->source;
8255 int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
8256 grn_obj_default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
8257 grn_obj *source, data;
8258 GRN_TEXT_INIT(&data, GRN_OBJ_DO_SHALLOW_COPY);
8259 GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
8260 for (i = 1; i <= n; i++, s++) {
8261 hook_data.section = i;
8262
8263 source = grn_ctx_at(ctx, *s);
8264 if (!source) {
8265 ERRCLR(ctx);
8266 continue;
8267 }
8268
8269 switch (source->header.type) {
8270 case GRN_TABLE_HASH_KEY :
8271 case GRN_TABLE_PAT_KEY :
8272 case GRN_TABLE_DAT_KEY :
8273 del_hook(ctx, source, GRN_HOOK_INSERT, &data);
8274 del_hook(ctx, source, GRN_HOOK_DELETE, &data);
8275 break;
8276 case GRN_COLUMN_FIX_SIZE :
8277 case GRN_COLUMN_VAR_SIZE :
8278 del_hook(ctx, source, GRN_HOOK_SET, &data);
8279 break;
8280 default :
8281 /* invalid target */
8282 break;
8283 }
8284 }
8285 grn_obj_close(ctx, &data);
8286}
8287
8288#define N_HOOK_ENTRIES 5
8289
8290grn_rc
8291grn_hook_pack(grn_ctx *ctx, grn_db_obj *obj, grn_obj *buf)
8292{
8293 grn_rc rc;
8294 grn_hook_entry e;
8295 for (e = 0; e < N_HOOK_ENTRIES; e++) {
8296 grn_hook *hooks;
8297 for (hooks = obj->hooks[e]; hooks; hooks = hooks->next) {
8298 grn_id id = hooks->proc ? hooks->proc->obj.id : 0;
8299 if ((rc = grn_text_benc(ctx, buf, id + 1))) { goto exit; }
8300 if ((rc = grn_text_benc(ctx, buf, hooks->hld_size))) { goto exit; }
8301 if ((rc = grn_bulk_write(ctx, buf, (char *)GRN_NEXT_ADDR(hooks), hooks->hld_size))) { goto exit; }
8302 }
8303 if ((rc = grn_text_benc(ctx, buf, 0))) { goto exit; }
8304 }
8305exit :
8306 return rc;
8307}
8308
8309static grn_rc
8310grn_hook_unpack(grn_ctx *ctx, grn_db_obj *obj, const char *buf, uint32_t buf_size)
8311{
8312 grn_hook_entry e;
8313 const uint8_t *p = (uint8_t *)buf, *pe = p + buf_size;
8314 for (e = 0; e < N_HOOK_ENTRIES; e++) {
8315 grn_hook *new, **last = &obj->hooks[e];
8316 for (;;) {
8317 grn_id id;
8318 uint32_t hld_size;
8319 GRN_B_DEC(id, p);
8320 if (!id--) { break; }
8321 if (p >= pe) { return GRN_FILE_CORRUPT; }
8322 GRN_B_DEC(hld_size, p);
8323 if (p >= pe) { return GRN_FILE_CORRUPT; }
8324 if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
8325 return GRN_NO_MEMORY_AVAILABLE;
8326 }
8327 if (id) {
8328 new->proc = (grn_proc *)grn_ctx_at(ctx, id);
8329 if (!new->proc) {
8330 GRN_FREE(new);
8331 return ctx->rc;
8332 }
8333 } else {
8334 new->proc = NULL;
8335 }
8336 if ((new->hld_size = hld_size)) {
8337 grn_memcpy(GRN_NEXT_ADDR(new), p, hld_size);
8338 p += hld_size;
8339 }
8340 *last = new;
8341 last = &new->next;
8342 if (p >= pe) { return GRN_FILE_CORRUPT; }
8343 }
8344 *last = NULL;
8345 }
8346 return GRN_SUCCESS;
8347}
8348
8349static void
8350grn_token_filters_pack(grn_ctx *ctx,
8351 grn_obj *token_filters,
8352 grn_obj *buffer)
8353{
8354 unsigned int i, n_token_filters;
8355
8356 n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
8357 for (i = 0; i < n_token_filters; i++) {
8358 grn_obj *token_filter = GRN_PTR_VALUE_AT(token_filters, i);
8359 grn_id token_filter_id;
8360
8361 token_filter_id = grn_obj_id(ctx, token_filter);
8362 GRN_RECORD_PUT(ctx, buffer, token_filter_id);
8363 }
8364}
8365
8366static grn_bool
8367grn_obj_encoded_spec_equal(grn_ctx *ctx,
8368 grn_obj *encoded_spec1,
8369 grn_obj *encoded_spec2)
8370{
8371 unsigned int i, n_elements;
8372
8373 if (encoded_spec1->header.type != GRN_VECTOR) {
8374 return GRN_FALSE;
8375 }
8376
8377 if (encoded_spec1->header.type != encoded_spec2->header.type) {
8378 return GRN_FALSE;
8379 }
8380
8381 n_elements = grn_vector_size(ctx, encoded_spec1);
8382 if (grn_vector_size(ctx, encoded_spec2) != n_elements) {
8383 return GRN_FALSE;
8384 }
8385
8386 for (i = 0; i < n_elements; i++) {
8387 const char *content1;
8388 const char *content2;
8389 unsigned int content_size1;
8390 unsigned int content_size2;
8391 unsigned int weight1;
8392 unsigned int weight2;
8393 grn_id domain1;
8394 grn_id domain2;
8395
8396 content_size1 = grn_vector_get_element(ctx,
8397 encoded_spec1,
8398 i,
8399 &content1,
8400 &weight1,
8401 &domain1);
8402 content_size2 = grn_vector_get_element(ctx,
8403 encoded_spec2,
8404 i,
8405 &content2,
8406 &weight2,
8407 &domain2);
8408 if (content_size1 != content_size2) {
8409 return GRN_FALSE;
8410 }
8411 if (memcmp(content1, content2, content_size1) != 0) {
8412 return GRN_FALSE;
8413 }
8414 if (weight1 != weight2) {
8415 return GRN_FALSE;
8416 }
8417 if (domain1 != domain2) {
8418 return GRN_FALSE;
8419 }
8420 }
8421
8422 return GRN_TRUE;
8423}
8424
8425void
8426grn_obj_spec_save(grn_ctx *ctx, grn_db_obj *obj)
8427{
8428 grn_db *s;
8429 grn_obj v, *b;
8430 grn_obj_spec spec;
8431 grn_bool need_update = GRN_TRUE;
8432
8433 if (obj->id & GRN_OBJ_TMP_OBJECT) { return; }
8434 if (!ctx->impl || !GRN_DB_OBJP(obj)) { return; }
8435 if (!(s = (grn_db *)ctx->impl->db) || !s->specs) { return; }
8436 if (obj->header.type == GRN_PROC && obj->range == GRN_ID_NIL) {
8437 return;
8438 }
8439 GRN_OBJ_INIT(&v, GRN_VECTOR, 0, GRN_DB_TEXT);
8440 if (!(b = grn_vector_body(ctx, &v))) { return; }
8441 spec.header = obj->header;
8442 spec.range = obj->range;
8443 grn_bulk_write(ctx, b, (void *)&spec, sizeof(grn_obj_spec));
8444 grn_vector_delimit(ctx, &v, 0, 0);
8445 if (obj->header.flags & GRN_OBJ_CUSTOM_NAME) {
8446 GRN_TEXT_PUTS(ctx, b, grn_obj_path(ctx, (grn_obj *)obj));
8447 }
8448 grn_vector_delimit(ctx, &v, 0, 0);
8449 grn_bulk_write(ctx, b, obj->source, obj->source_size);
8450 grn_vector_delimit(ctx, &v, 0, 0);
8451 grn_hook_pack(ctx, obj, b);
8452 grn_vector_delimit(ctx, &v, 0, 0);
8453 switch (obj->header.type) {
8454 case GRN_TABLE_HASH_KEY :
8455 grn_token_filters_pack(ctx, &(((grn_hash *)obj)->token_filters), b);
8456 grn_vector_delimit(ctx, &v, 0, 0);
8457 break;
8458 case GRN_TABLE_PAT_KEY :
8459 grn_token_filters_pack(ctx, &(((grn_pat *)obj)->token_filters), b);
8460 grn_vector_delimit(ctx, &v, 0, 0);
8461 break;
8462 case GRN_TABLE_DAT_KEY :
8463 grn_token_filters_pack(ctx, &(((grn_dat *)obj)->token_filters), b);
8464 grn_vector_delimit(ctx, &v, 0, 0);
8465 break;
8466 case GRN_EXPR :
8467 grn_expr_pack(ctx, b, (grn_obj *)obj);
8468 grn_vector_delimit(ctx, &v, 0, 0);
8469 break;
8470 }
8471
8472 {
8473 grn_io_win jw;
8474 uint32_t current_spec_raw_len;
8475 char *current_spec_raw;
8476
8477 current_spec_raw = grn_ja_ref(ctx,
8478 s->specs,
8479 obj->id,
8480 &jw,
8481 &current_spec_raw_len);
8482 if (current_spec_raw) {
8483 grn_rc rc;
8484 grn_obj current_spec;
8485
8486 GRN_OBJ_INIT(&current_spec, GRN_VECTOR, 0, GRN_DB_TEXT);
8487 rc = grn_vector_decode(ctx,
8488 &current_spec,
8489 current_spec_raw,
8490 current_spec_raw_len);
8491 if (rc == GRN_SUCCESS) {
8492 need_update = !grn_obj_encoded_spec_equal(ctx, &v, &current_spec);
8493 }
8494 GRN_OBJ_FIN(ctx, &current_spec);
8495 grn_ja_unref(ctx, &jw);
8496 }
8497 }
8498
8499 if (!need_update) {
8500 grn_obj_close(ctx, &v);
8501 return;
8502 }
8503
8504 {
8505 const char *name;
8506 uint32_t name_size = 0;
8507 const char *range_name = NULL;
8508 uint32_t range_name_size = 0;
8509
8510 name = _grn_table_key(ctx, s->keys, obj->id, &name_size);
8511 switch (obj->header.type) {
8512 case GRN_TABLE_HASH_KEY :
8513 case GRN_TABLE_PAT_KEY :
8514 case GRN_TABLE_DAT_KEY :
8515 case GRN_TABLE_NO_KEY :
8516 case GRN_COLUMN_FIX_SIZE :
8517 case GRN_COLUMN_VAR_SIZE :
8518 case GRN_COLUMN_INDEX :
8519 if (obj->range != GRN_ID_NIL) {
8520 range_name = _grn_table_key(ctx, s->keys, obj->range, &range_name_size);
8521 }
8522 break;
8523 default :
8524 break;
8525 }
8526 /* TODO: reduce log level. */
8527 GRN_LOG(ctx, GRN_LOG_NOTICE,
8528 "spec:%u:update:%.*s:%u(%s):%u%s%.*s%s",
8529 obj->id,
8530 name_size, name,
8531 obj->header.type,
8532 grn_obj_type_to_string(obj->header.type),
8533 obj->range,
8534 range_name_size == 0 ? "" : "(",
8535 range_name_size, range_name,
8536 range_name_size == 0 ? "" : ")");
8537 }
8538 grn_ja_putv(ctx, s->specs, obj->id, &v, 0);
8539 grn_obj_close(ctx, &v);
8540}
8541
8542inline static void
8543grn_obj_set_info_source_invalid_lexicon_error(grn_ctx *ctx,
8544 const char *message,
8545 grn_obj *actual_type,
8546 grn_obj *expected_type,
8547 grn_obj *index_column,
8548 grn_obj *source)
8549{
8550 char actual_type_name[GRN_TABLE_MAX_KEY_SIZE];
8551 int actual_type_name_size;
8552 char expected_type_name[GRN_TABLE_MAX_KEY_SIZE];
8553 int expected_type_name_size;
8554 char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
8555 int index_column_name_size;
8556 char source_name[GRN_TABLE_MAX_KEY_SIZE];
8557 int source_name_size;
8558
8559 actual_type_name_size = grn_obj_name(ctx, actual_type,
8560 actual_type_name,
8561 GRN_TABLE_MAX_KEY_SIZE);
8562 expected_type_name_size = grn_obj_name(ctx, expected_type,
8563 expected_type_name,
8564 GRN_TABLE_MAX_KEY_SIZE);
8565 index_column_name_size = grn_obj_name(ctx, index_column,
8566 index_column_name,
8567 GRN_TABLE_MAX_KEY_SIZE);
8568
8569 source_name_size = grn_obj_name(ctx, source,
8570 source_name, GRN_TABLE_MAX_KEY_SIZE);
8571 if (grn_obj_is_table(ctx, source)) {
8572 source_name[source_name_size] = '\0';
8573 grn_strncat(source_name,
8574 GRN_TABLE_MAX_KEY_SIZE,
8575 "._key",
8576 GRN_TABLE_MAX_KEY_SIZE - source_name_size - 1);
8577 source_name_size = strlen(source_name);
8578 }
8579
8580 ERR(GRN_INVALID_ARGUMENT,
8581 "[column][index][source] %s: "
8582 "<%.*s> -> <%.*s>: "
8583 "index-column:<%.*s> "
8584 "source:<%.*s>",
8585 message,
8586 actual_type_name_size, actual_type_name,
8587 expected_type_name_size, expected_type_name,
8588 index_column_name_size, index_column_name,
8589 source_name_size, source_name);
8590}
8591
8592inline static grn_rc
8593grn_obj_set_info_source_validate(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8594{
8595 grn_id lexicon_id;
8596 grn_obj *lexicon = NULL;
8597 grn_id lexicon_domain_id;
8598 grn_obj *lexicon_domain = NULL;
8599 grn_bool lexicon_domain_is_table;
8600 grn_bool lexicon_have_tokenizer;
8601 grn_id *source_ids;
8602 int i, n_source_ids;
8603
8604 lexicon_id = obj->header.domain;
8605 lexicon = grn_ctx_at(ctx, lexicon_id);
8606 if (!lexicon) {
8607 goto exit;
8608 }
8609
8610 lexicon_domain_id = lexicon->header.domain;
8611 lexicon_domain = grn_ctx_at(ctx, lexicon_domain_id);
8612 if (!lexicon_domain) {
8613 goto exit;
8614 }
8615
8616 source_ids = (grn_id *)GRN_BULK_HEAD(value);
8617 n_source_ids = GRN_BULK_VSIZE(value) / sizeof(grn_id);
8618 if (n_source_ids > 1 && !(obj->header.flags & GRN_OBJ_WITH_SECTION)) {
8619 char index_name[GRN_TABLE_MAX_KEY_SIZE];
8620 int index_name_size;
8621 index_name_size = grn_obj_name(ctx, obj,
8622 index_name, GRN_TABLE_MAX_KEY_SIZE);
8623 ERR(GRN_INVALID_ARGUMENT,
8624 "grn_obj_set_info(): GRN_INFO_SOURCE: "
8625 "multi column index must be created with WITH_SECTION flag: <%.*s>",
8626 index_name_size, index_name);
8627 goto exit;
8628 }
8629
8630 lexicon_domain_is_table = grn_obj_is_table(ctx, lexicon_domain);
8631 {
8632 grn_obj *tokenizer;
8633 grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
8634 lexicon_have_tokenizer = (tokenizer != NULL);
8635 }
8636
8637 for (i = 0; i < n_source_ids; i++) {
8638 grn_id source_id = source_ids[i];
8639 grn_obj *source;
8640 grn_id source_type_id;
8641 grn_obj *source_type;
8642
8643 source = grn_ctx_at(ctx, source_id);
8644 if (!source) {
8645 continue;
8646 }
8647 if (grn_obj_is_table(ctx, source)) {
8648 source_type_id = source->header.domain;
8649 } else {
8650 source_type_id = DB_OBJ(source)->range;
8651 }
8652 source_type = grn_ctx_at(ctx, source_type_id);
8653 if (!lexicon_have_tokenizer) {
8654 if (grn_obj_is_table(ctx, source_type)) {
8655 if (lexicon_id != source_type_id) {
8656 grn_obj_set_info_source_invalid_lexicon_error(
8657 ctx,
8658 "index table must equal to source type",
8659 lexicon,
8660 source_type,
8661 obj,
8662 source);
8663 }
8664 } else {
8665 if (!(lexicon_domain_id == source_type_id ||
8666 (grn_type_id_is_text_family(ctx, lexicon_domain_id) &&
8667 grn_type_id_is_text_family(ctx, source_type_id)))) {
8668 grn_obj_set_info_source_invalid_lexicon_error(
8669 ctx,
8670 "index table's key must equal source type",
8671 lexicon_domain,
8672 source_type,
8673 obj,
8674 source);
8675 }
8676 }
8677 }
8678 grn_obj_unlink(ctx, source);
8679 if (ctx->rc != GRN_SUCCESS) {
8680 goto exit;
8681 }
8682 }
8683
8684exit:
8685 if (lexicon) {
8686 grn_obj_unlink(ctx, lexicon);
8687 }
8688 if (lexicon_domain) {
8689 grn_obj_unlink(ctx, lexicon_domain);
8690 }
8691 return ctx->rc;
8692}
8693
8694inline static void
8695grn_obj_set_info_source_log(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8696{
8697 grn_obj buf;
8698 grn_id *vp = (grn_id *)GRN_BULK_HEAD(value);
8699 uint32_t vs = GRN_BULK_VSIZE(value), s = 0;
8700 grn_id id;
8701 const char *n;
8702
8703 id = DB_OBJ(obj)->id;
8704 n = _grn_table_key(ctx, ctx->impl->db, id, &s);
8705 GRN_TEXT_INIT(&buf, 0);
8706 GRN_TEXT_PUT(ctx, &buf, n, s);
8707 GRN_TEXT_PUTC(ctx, &buf, ' ');
8708 while (vs) {
8709 n = _grn_table_key(ctx, ctx->impl->db, *vp++, &s);
8710 GRN_TEXT_PUT(ctx, &buf, n, s);
8711 vs -= sizeof(grn_id);
8712 if (vs) { GRN_TEXT_PUTC(ctx, &buf, ','); }
8713 }
8714 GRN_LOG(ctx, GRN_LOG_NOTICE,
8715 "DDL:%u:set_source %.*s",
8716 id,
8717 (int)GRN_BULK_VSIZE(&buf), GRN_BULK_HEAD(&buf));
8718 GRN_OBJ_FIN(ctx, &buf);
8719}
8720
8721inline static grn_rc
8722grn_obj_set_info_source_update(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8723{
8724 void *v = GRN_BULK_HEAD(value);
8725 uint32_t s = GRN_BULK_VSIZE(value);
8726 if (s) {
8727 void *v2 = GRN_MALLOC(s);
8728 if (!v2) {
8729 return ctx->rc;
8730 }
8731 grn_memcpy(v2, v, s);
8732 if (DB_OBJ(obj)->source) { GRN_FREE(DB_OBJ(obj)->source); }
8733 DB_OBJ(obj)->source = v2;
8734 DB_OBJ(obj)->source_size = s;
8735
8736 if (obj->header.type == GRN_COLUMN_INDEX) {
8737 update_source_hook(ctx, obj);
8738 grn_index_column_build(ctx, obj);
8739 }
8740 } else {
8741 DB_OBJ(obj)->source = NULL;
8742 DB_OBJ(obj)->source_size = 0;
8743 }
8744
8745 return GRN_SUCCESS;
8746}
8747
8748inline static grn_rc
8749grn_obj_set_info_source(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
8750{
8751 grn_rc rc;
8752
8753 rc = grn_obj_set_info_source_validate(ctx, obj, value);
8754 if (rc != GRN_SUCCESS) {
8755 return rc;
8756 }
8757 grn_obj_set_info_source_log(ctx, obj, value);
8758 rc = grn_obj_set_info_source_update(ctx, obj, value);
8759 if (rc != GRN_SUCCESS) {
8760 return rc;
8761 }
8762 grn_obj_spec_save(ctx, DB_OBJ(obj));
8763
8764 return rc;
8765}
8766
8767static grn_rc
8768grn_obj_set_info_token_filters(grn_ctx *ctx,
8769 grn_obj *table,
8770 grn_obj *token_filters)
8771{
8772 grn_obj *current_token_filters;
8773 unsigned int i, n_current_token_filters, n_token_filters;
8774 grn_obj token_filter_names;
8775
8776 switch (table->header.type) {
8777 case GRN_TABLE_HASH_KEY :
8778 current_token_filters = &(((grn_hash *)table)->token_filters);
8779 break;
8780 case GRN_TABLE_PAT_KEY :
8781 current_token_filters = &(((grn_pat *)table)->token_filters);
8782 break;
8783 case GRN_TABLE_DAT_KEY :
8784 current_token_filters = &(((grn_dat *)table)->token_filters);
8785 break;
8786 default :
8787 /* TODO: Show type name instead of type ID */
8788 ERR(GRN_INVALID_ARGUMENT,
8789 "[info][set][token-filters] target object must be one of "
8790 "GRN_TABLE_HASH_KEY, GRN_TABLE_PAT_KEY and GRN_TABLE_DAT_KEY: %d",
8791 table->header.type);
8792 return ctx->rc;
8793 }
8794
8795 n_current_token_filters =
8796 GRN_BULK_VSIZE(current_token_filters) / sizeof(grn_obj *);
8797 n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
8798
8799 GRN_TEXT_INIT(&token_filter_names, 0);
8800 GRN_BULK_REWIND(current_token_filters);
8801 for (i = 0; i < n_token_filters; i++) {
8802 grn_obj *token_filter = GRN_PTR_VALUE_AT(token_filters, i);
8803 char token_filter_name[GRN_TABLE_MAX_KEY_SIZE];
8804 unsigned int token_filter_name_size;
8805
8806 GRN_PTR_PUT(ctx, current_token_filters, token_filter);
8807
8808 if (i > 0) {
8809 GRN_TEXT_PUTC(ctx, &token_filter_names, ',');
8810 }
8811 token_filter_name_size = grn_obj_name(ctx,
8812 token_filter,
8813 token_filter_name,
8814 GRN_TABLE_MAX_KEY_SIZE);
8815 GRN_TEXT_PUT(ctx,
8816 &token_filter_names,
8817 token_filter_name,
8818 token_filter_name_size);
8819 }
8820 if (n_token_filters > 0 || n_token_filters != n_current_token_filters) {
8821 GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:%u:set_token_filters %.*s",
8822 DB_OBJ(table)->id,
8823 (int)GRN_BULK_VSIZE(&token_filter_names),
8824 GRN_BULK_HEAD(&token_filter_names));
8825 }
8826 GRN_OBJ_FIN(ctx, &token_filter_names);
8827 grn_obj_spec_save(ctx, DB_OBJ(table));
8828
8829 return GRN_SUCCESS;
8830}
8831
8832grn_rc
8833grn_obj_set_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *value)
8834{
8835 grn_rc rc = GRN_INVALID_ARGUMENT;
8836 GRN_API_ENTER;
8837 if (!obj) {
8838 ERR(GRN_INVALID_ARGUMENT, "grn_obj_set_info failed");
8839 goto exit;
8840 }
8841 switch (type) {
8842 case GRN_INFO_SOURCE :
8843 if (!GRN_DB_OBJP(obj)) {
8844 ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
8845 goto exit;
8846 }
8847 rc = grn_obj_set_info_source(ctx, obj, value);
8848 break;
8849 case GRN_INFO_DEFAULT_TOKENIZER :
8850 if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
8851 switch (DB_OBJ(obj)->header.type) {
8852 case GRN_TABLE_HASH_KEY :
8853 ((grn_hash *)obj)->tokenizer = value;
8854 ((grn_hash *)obj)->header.common->tokenizer = grn_obj_id(ctx, value);
8855 rc = GRN_SUCCESS;
8856 break;
8857 case GRN_TABLE_PAT_KEY :
8858 ((grn_pat *)obj)->tokenizer = value;
8859 ((grn_pat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
8860 rc = GRN_SUCCESS;
8861 break;
8862 case GRN_TABLE_DAT_KEY :
8863 ((grn_dat *)obj)->tokenizer = value;
8864 ((grn_dat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
8865 rc = GRN_SUCCESS;
8866 break;
8867 }
8868 }
8869 break;
8870 case GRN_INFO_NORMALIZER :
8871 if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
8872 switch (DB_OBJ(obj)->header.type) {
8873 case GRN_TABLE_HASH_KEY :
8874 ((grn_hash *)obj)->normalizer = value;
8875 ((grn_hash *)obj)->header.common->normalizer = grn_obj_id(ctx, value);
8876 rc = GRN_SUCCESS;
8877 break;
8878 case GRN_TABLE_PAT_KEY :
8879 ((grn_pat *)obj)->normalizer = value;
8880 ((grn_pat *)obj)->header->normalizer = grn_obj_id(ctx, value);
8881 rc = GRN_SUCCESS;
8882 break;
8883 case GRN_TABLE_DAT_KEY :
8884 ((grn_dat *)obj)->normalizer = value;
8885 ((grn_dat *)obj)->header->normalizer = grn_obj_id(ctx, value);
8886 rc = GRN_SUCCESS;
8887 break;
8888 }
8889 }
8890 break;
8891 case GRN_INFO_TOKEN_FILTERS :
8892 rc = grn_obj_set_info_token_filters(ctx, obj, value);
8893 break;
8894 default :
8895 /* todo */
8896 break;
8897 }
8898exit :
8899 GRN_API_RETURN(rc);
8900}
8901
8902grn_obj *
8903grn_obj_get_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
8904 grn_info_type type, grn_obj *valuebuf)
8905{
8906 GRN_API_ENTER;
8907 GRN_API_RETURN(valuebuf);
8908}
8909
8910grn_rc
8911grn_obj_set_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
8912 grn_info_type type, grn_obj *value)
8913{
8914 GRN_API_ENTER;
8915 GRN_API_RETURN(GRN_SUCCESS);
8916}
8917
8918static void
8919grn_hook_free(grn_ctx *ctx, grn_hook *h)
8920{
8921 grn_hook *curr, *next;
8922 for (curr = h; curr; curr = next) {
8923 next = curr->next;
8924 GRN_FREE(curr);
8925 }
8926}
8927
8928grn_rc
8929grn_obj_add_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
8930 int offset, grn_obj *proc, grn_obj *hld)
8931{
8932 grn_rc rc = GRN_SUCCESS;
8933 GRN_API_ENTER;
8934 if (!GRN_DB_OBJP(obj)) {
8935 rc = GRN_INVALID_ARGUMENT;
8936 } else {
8937 int i;
8938 void *hld_value = NULL;
8939 uint32_t hld_size = 0;
8940 grn_hook *new, **last = &DB_OBJ(obj)->hooks[entry];
8941 if (hld) {
8942 hld_value = GRN_BULK_HEAD(hld);
8943 hld_size = GRN_BULK_VSIZE(hld);
8944 }
8945 if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
8946 rc = GRN_NO_MEMORY_AVAILABLE;
8947 goto exit;
8948 }
8949 new->proc = (grn_proc *)proc;
8950 new->hld_size = hld_size;
8951 if (hld_size) {
8952 grn_memcpy(GRN_NEXT_ADDR(new), hld_value, hld_size);
8953 }
8954 for (i = 0; i != offset && *last; i++) { last = &(*last)->next; }
8955 new->next = *last;
8956 *last = new;
8957 grn_obj_spec_save(ctx, DB_OBJ(obj));
8958 }
8959exit :
8960 GRN_API_RETURN(rc);
8961}
8962
8963int
8964grn_obj_get_nhooks(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry)
8965{
8966 int res = 0;
8967 GRN_API_ENTER;
8968 {
8969 grn_hook *hook = DB_OBJ(obj)->hooks[entry];
8970 while (hook) {
8971 res++;
8972 hook = hook->next;
8973 }
8974 }
8975 GRN_API_RETURN(res);
8976}
8977
8978grn_obj *
8979grn_obj_get_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
8980 int offset, grn_obj *hldbuf)
8981{
8982 grn_obj *res = NULL;
8983 GRN_API_ENTER;
8984 {
8985 int i;
8986 grn_hook *hook = DB_OBJ(obj)->hooks[entry];
8987 for (i = 0; i < offset; i++) {
8988 hook = hook->next;
8989 if (!hook) { return NULL; }
8990 }
8991 res = (grn_obj *)hook->proc;
8992 grn_bulk_write(ctx, hldbuf, (char *)GRN_NEXT_ADDR(hook), hook->hld_size);
8993 }
8994 GRN_API_RETURN(res);
8995}
8996
8997grn_rc
8998grn_obj_delete_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, int offset)
8999{
9000 GRN_API_ENTER;
9001 {
9002 int i = 0;
9003 grn_hook *h, **last = &DB_OBJ(obj)->hooks[entry];
9004 for (;;) {
9005 if (!(h = *last)) { return GRN_INVALID_ARGUMENT; }
9006 if (++i > offset) { break; }
9007 last = &h->next;
9008 }
9009 *last = h->next;
9010 GRN_FREE(h);
9011 }
9012 grn_obj_spec_save(ctx, DB_OBJ(obj));
9013 GRN_API_RETURN(GRN_SUCCESS);
9014}
9015
9016static grn_rc
9017remove_index(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry)
9018{
9019 grn_rc rc = GRN_SUCCESS;
9020 grn_hook *h0, *hooks = DB_OBJ(obj)->hooks[entry];
9021 DB_OBJ(obj)->hooks[entry] = NULL; /* avoid mutual recursive call */
9022 while (hooks) {
9023 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
9024 grn_obj *target = grn_ctx_at(ctx, data->target);
9025 if (!target) {
9026 char name[GRN_TABLE_MAX_KEY_SIZE];
9027 int length;
9028 char hook_name[GRN_TABLE_MAX_KEY_SIZE];
9029 int hook_name_length;
9030
9031 length = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
9032 hook_name_length = grn_table_get_key(ctx,
9033 ctx->impl->db,
9034 data->target,
9035 hook_name,
9036 GRN_TABLE_MAX_KEY_SIZE);
9037 ERR(GRN_OBJECT_CORRUPT,
9038 "[column][remove][index] "
9039 "hook has a dangling reference: <%.*s> -> <%.*s>",
9040 length, name,
9041 hook_name_length, hook_name);
9042 rc = ctx->rc;
9043 } else if (target->header.type == GRN_COLUMN_INDEX) {
9044 //TODO: multicolumn MULTI_COLUMN_INDEXP
9045 rc = _grn_obj_remove(ctx, target, GRN_FALSE);
9046 } else {
9047 //TODO: err
9048 char fn[GRN_TABLE_MAX_KEY_SIZE];
9049 int flen;
9050 flen = grn_obj_name(ctx, target, fn, GRN_TABLE_MAX_KEY_SIZE);
9051 fn[flen] = '\0';
9052 ERR(GRN_UNKNOWN_ERROR, "column has unsupported hooks, col=%s",fn);
9053 rc = ctx->rc;
9054 }
9055 if (rc != GRN_SUCCESS) {
9056 DB_OBJ(obj)->hooks[entry] = hooks;
9057 break;
9058 }
9059 h0 = hooks;
9060 hooks = hooks->next;
9061 GRN_FREE(h0);
9062 }
9063 return rc;
9064}
9065
9066static grn_rc
9067remove_columns(grn_ctx *ctx, grn_obj *obj)
9068{
9069 grn_rc rc = GRN_SUCCESS;
9070 grn_hash *cols;
9071 if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
9072 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
9073 if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
9074 GRN_HASH_EACH_BEGIN(ctx, cols, cursor, id) {
9075 grn_id *key;
9076 grn_obj *col;
9077
9078 grn_hash_cursor_get_key(ctx, cursor, (void **)&key);
9079 col = grn_ctx_at(ctx, *key);
9080
9081 if (!col) {
9082 char name[GRN_TABLE_MAX_KEY_SIZE];
9083 int name_size;
9084 name_size = grn_table_get_key(ctx, ctx->impl->db, *key,
9085 name, GRN_TABLE_MAX_KEY_SIZE);
9086 if (ctx->rc == GRN_SUCCESS) {
9087 ERR(GRN_INVALID_ARGUMENT,
9088 "[object][remove] column is broken: <%.*s>",
9089 name_size, name);
9090 } else {
9091 ERR(ctx->rc,
9092 "[object][remove] column is broken: <%.*s>: %s",
9093 name_size, name,
9094 ctx->errbuf);
9095 }
9096 rc = ctx->rc;
9097 break;
9098 }
9099
9100 rc = _grn_obj_remove(ctx, col, GRN_FALSE);
9101 if (rc != GRN_SUCCESS) {
9102 grn_obj_unlink(ctx, col);
9103 break;
9104 }
9105 } GRN_HASH_EACH_END(ctx, cursor);
9106 }
9107 grn_hash_close(ctx, cols);
9108 }
9109 return rc;
9110}
9111
9112static grn_rc
9113_grn_obj_remove_db_index_columns(grn_ctx *ctx, grn_obj *db)
9114{
9115 grn_rc rc = GRN_SUCCESS;
9116 grn_table_cursor *cur;
9117 if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9118 grn_id id;
9119 while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9120 grn_obj *obj = grn_ctx_at(ctx, id);
9121 if (obj && obj->header.type == GRN_COLUMN_INDEX) {
9122 rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9123 if (rc != GRN_SUCCESS) {
9124 grn_obj_unlink(ctx, obj);
9125 break;
9126 }
9127 }
9128 }
9129 grn_table_cursor_close(ctx, cur);
9130 }
9131 return rc;
9132}
9133
9134static grn_rc
9135_grn_obj_remove_db_reference_columns(grn_ctx *ctx, grn_obj *db)
9136{
9137 grn_rc rc = GRN_SUCCESS;
9138 grn_table_cursor *cur;
9139 if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9140 grn_id id;
9141 while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9142 grn_obj *obj = grn_ctx_at(ctx, id);
9143 grn_obj *range = NULL;
9144
9145 if (!obj) {
9146 continue;
9147 }
9148
9149 switch (obj->header.type) {
9150 case GRN_COLUMN_FIX_SIZE :
9151 case GRN_COLUMN_VAR_SIZE :
9152 if (!DB_OBJ(obj)->range) {
9153 break;
9154 }
9155
9156 range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
9157 if (!range) {
9158 break;
9159 }
9160
9161 switch (range->header.type) {
9162 case GRN_TABLE_NO_KEY :
9163 case GRN_TABLE_HASH_KEY :
9164 case GRN_TABLE_PAT_KEY :
9165 case GRN_TABLE_DAT_KEY :
9166 rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9167 break;
9168 }
9169 break;
9170 }
9171
9172 if (rc != GRN_SUCCESS) {
9173 break;
9174 }
9175 }
9176 grn_table_cursor_close(ctx, cur);
9177 }
9178 return rc;
9179}
9180
9181static grn_rc
9182_grn_obj_remove_db_reference_tables(grn_ctx *ctx, grn_obj *db)
9183{
9184 grn_rc rc = GRN_SUCCESS;
9185 grn_table_cursor *cur;
9186 if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9187 grn_id id;
9188 while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9189 grn_obj *obj = grn_ctx_at(ctx, id);
9190 grn_obj *domain = NULL;
9191
9192 if (!obj) {
9193 continue;
9194 }
9195
9196 switch (obj->header.type) {
9197 case GRN_TABLE_HASH_KEY :
9198 case GRN_TABLE_PAT_KEY :
9199 case GRN_TABLE_DAT_KEY :
9200 if (!obj->header.domain) {
9201 break;
9202 }
9203
9204 domain = grn_ctx_at(ctx, obj->header.domain);
9205 if (!domain) {
9206 break;
9207 }
9208
9209 switch (domain->header.type) {
9210 case GRN_TABLE_NO_KEY :
9211 case GRN_TABLE_HASH_KEY :
9212 case GRN_TABLE_PAT_KEY :
9213 case GRN_TABLE_DAT_KEY :
9214 rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9215 break;
9216 }
9217 break;
9218 }
9219
9220 if (rc != GRN_SUCCESS) {
9221 break;
9222 }
9223 }
9224 grn_table_cursor_close(ctx, cur);
9225 }
9226 return rc;
9227}
9228
9229static grn_rc
9230_grn_obj_remove_db_all_tables(grn_ctx *ctx, grn_obj *db)
9231{
9232 grn_rc rc = GRN_SUCCESS;
9233 grn_table_cursor *cur;
9234 if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
9235 grn_id id;
9236 while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
9237 grn_obj *obj = grn_ctx_at(ctx, id);
9238
9239 if (!obj) {
9240 continue;
9241 }
9242
9243 switch (obj->header.type) {
9244 case GRN_TABLE_NO_KEY :
9245 case GRN_TABLE_HASH_KEY :
9246 case GRN_TABLE_PAT_KEY :
9247 case GRN_TABLE_DAT_KEY :
9248 rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9249 break;
9250 }
9251
9252 if (rc != GRN_SUCCESS) {
9253 break;
9254 }
9255 }
9256 grn_table_cursor_close(ctx, cur);
9257 }
9258 return rc;
9259}
9260
9261static grn_rc
9262_grn_obj_remove_db(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9263 const char *path)
9264{
9265 grn_rc rc = GRN_SUCCESS;
9266 const char *io_spath;
9267 char *spath;
9268 grn_db *s = (grn_db *)db;
9269 unsigned char key_type;
9270
9271 rc = _grn_obj_remove_db_index_columns(ctx, db);
9272 if (rc != GRN_SUCCESS) { return rc; }
9273 rc = _grn_obj_remove_db_reference_columns(ctx, db);
9274 if (rc != GRN_SUCCESS) { return rc; }
9275 rc = _grn_obj_remove_db_reference_tables(ctx, db);
9276 if (rc != GRN_SUCCESS) { return rc; }
9277 rc = _grn_obj_remove_db_all_tables(ctx, db);
9278 if (rc != GRN_SUCCESS) { return rc; }
9279
9280 if (s->specs &&
9281 (io_spath = grn_obj_path(ctx, (grn_obj *)s->specs)) && *io_spath != '\0') {
9282 if (!(spath = GRN_STRDUP(io_spath))) {
9283 ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_spath);
9284 return ctx->rc;
9285 }
9286 } else {
9287 spath = NULL;
9288 }
9289
9290 key_type = s->keys->header.type;
9291
9292 rc = grn_obj_close(ctx, obj);
9293 if (rc != GRN_SUCCESS) {
9294 if (spath) {
9295 GRN_FREE(spath);
9296 }
9297 return rc;
9298 }
9299
9300 if (spath) {
9301 rc = grn_ja_remove(ctx, spath);
9302 GRN_FREE(spath);
9303 if (rc != GRN_SUCCESS) { return rc; }
9304 }
9305
9306 if (path) {
9307 switch (key_type) {
9308 case GRN_TABLE_PAT_KEY :
9309 rc = grn_pat_remove(ctx, path);
9310 break;
9311 case GRN_TABLE_DAT_KEY :
9312 rc = grn_dat_remove(ctx, path);
9313 break;
9314 }
9315 if (rc == GRN_SUCCESS) {
9316 rc = grn_db_config_remove(ctx, path);
9317 } else {
9318 grn_db_config_remove(ctx, path);
9319 }
9320 }
9321
9322 return rc;
9323}
9324
9325static grn_rc
9326remove_reference_tables(grn_ctx *ctx, grn_obj *table, grn_obj *db)
9327{
9328 grn_rc rc = GRN_SUCCESS;
9329 grn_bool is_close_opened_object_mode = GRN_FALSE;
9330 grn_id table_id;
9331 char table_name[GRN_TABLE_MAX_KEY_SIZE];
9332 int table_name_size;
9333 grn_table_cursor *cursor;
9334
9335 if (grn_thread_get_limit() == 1) {
9336 is_close_opened_object_mode = GRN_TRUE;
9337 }
9338
9339 table_id = DB_OBJ(table)->id;
9340 table_name_size = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
9341 if ((cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
9342 GRN_CURSOR_BY_ID))) {
9343 grn_id id;
9344 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
9345 grn_obj *object;
9346 grn_bool is_removed = GRN_FALSE;
9347
9348 if (is_close_opened_object_mode) {
9349 grn_ctx_push_temporary_open_space(ctx);
9350 }
9351
9352 object = grn_ctx_at(ctx, id);
9353 if (!object) {
9354 ERRCLR(ctx);
9355 if (is_close_opened_object_mode) {
9356 grn_ctx_pop_temporary_open_space(ctx);
9357 }
9358 continue;
9359 }
9360
9361 switch (object->header.type) {
9362 case GRN_TABLE_HASH_KEY :
9363 case GRN_TABLE_PAT_KEY :
9364 case GRN_TABLE_DAT_KEY :
9365 if (DB_OBJ(object)->id == table_id) {
9366 break;
9367 }
9368
9369 if (object->header.domain == table_id) {
9370 rc = _grn_obj_remove(ctx, object, GRN_TRUE);
9371 is_removed = (grn_table_at(ctx, db, id) == GRN_ID_NIL);
9372 }
9373 break;
9374 case GRN_TABLE_NO_KEY :
9375 break;
9376 case GRN_COLUMN_VAR_SIZE :
9377 case GRN_COLUMN_FIX_SIZE :
9378 if (object->header.domain == table_id) {
9379 break;
9380 }
9381 if (DB_OBJ(object)->range == table_id) {
9382 rc = _grn_obj_remove(ctx, object, GRN_FALSE);
9383 is_removed = (grn_table_at(ctx, db, id) == GRN_ID_NIL);
9384 }
9385 break;
9386 case GRN_COLUMN_INDEX :
9387 break;
9388 default:
9389 break;
9390 }
9391
9392 if (!is_removed) {
9393 grn_obj_unlink(ctx, object);
9394 }
9395
9396 if (is_close_opened_object_mode) {
9397 grn_ctx_pop_temporary_open_space(ctx);
9398 }
9399
9400 if (rc != GRN_SUCCESS) {
9401 break;
9402 }
9403 }
9404 grn_table_cursor_close(ctx, cursor);
9405 }
9406
9407 return rc;
9408}
9409
9410static grn_bool
9411is_removable_table(grn_ctx *ctx, grn_obj *table, grn_obj *db)
9412{
9413 grn_id table_id;
9414 grn_id reference_object_id;
9415
9416 table_id = DB_OBJ(table)->id;
9417 if (table_id & GRN_OBJ_TMP_OBJECT) {
9418 return GRN_TRUE;
9419 }
9420
9421 reference_object_id = grn_table_find_reference_object(ctx, table);
9422 if (reference_object_id == GRN_ID_NIL) {
9423 return GRN_TRUE;
9424 }
9425
9426 {
9427 grn_obj *db;
9428 const char *table_name;
9429 int table_name_size;
9430 grn_obj *reference_object;
9431 const char *reference_object_name;
9432 int reference_object_name_size;
9433
9434 db = grn_ctx_db(ctx);
9435
9436 table_name = _grn_table_key(ctx, db, table_id,&table_name_size);
9437
9438 reference_object = grn_ctx_at(ctx, reference_object_id);
9439 reference_object_name = _grn_table_key(ctx,
9440 db,
9441 reference_object_id,
9442 &reference_object_name_size);
9443 if (reference_object) {
9444 if (grn_obj_is_table(ctx, reference_object)) {
9445 ERR(GRN_OPERATION_NOT_PERMITTED,
9446 "[table][remove] a table that references the table exists: "
9447 "<%.*s._key> -> <%.*s>",
9448 reference_object_name_size, reference_object_name,
9449 table_name_size, table_name);
9450 } else {
9451 ERR(GRN_OPERATION_NOT_PERMITTED,
9452 "[table][remove] a column that references the table exists: "
9453 "<%.*s> -> <%.*s>",
9454 reference_object_name_size, reference_object_name,
9455 table_name_size, table_name);
9456 }
9457 } else {
9458 ERR(GRN_OPERATION_NOT_PERMITTED,
9459 "[table][remove] a dangling object that references the table exists: "
9460 "<%.*s(%u)> -> <%.*s>",
9461 reference_object_name_size,
9462 reference_object_name,
9463 reference_object_id,
9464 table_name_size, table_name);
9465 }
9466 }
9467
9468 return GRN_FALSE;
9469}
9470
9471static inline grn_rc
9472_grn_obj_remove_spec(grn_ctx *ctx, grn_obj *db, grn_id id, uint8_t type)
9473{
9474 const char *name;
9475 uint32_t name_size = 0;
9476
9477 name = _grn_table_key(ctx, db, id, &name_size);
9478 /* TODO: reduce log level. */
9479 GRN_LOG(ctx, GRN_LOG_NOTICE,
9480 "spec:%u:remove:%.*s:%u(%s)",
9481 id,
9482 name_size, name,
9483 type,
9484 grn_obj_type_to_string(type));
9485
9486 return grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
9487}
9488
9489static grn_rc
9490_grn_obj_remove_pat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9491 const char *path, grn_bool dependent)
9492{
9493 grn_rc rc = GRN_SUCCESS;
9494 uint8_t type;
9495
9496 type = obj->header.type;
9497
9498 if (dependent) {
9499 rc = remove_reference_tables(ctx, obj, db);
9500 if (rc != GRN_SUCCESS) {
9501 return rc;
9502 }
9503 } else {
9504 if (!is_removable_table(ctx, obj, db)) {
9505 return ctx->rc;
9506 }
9507 }
9508
9509 rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
9510 if (rc != GRN_SUCCESS) { return rc; }
9511 rc = remove_columns(ctx, obj);
9512 if (rc != GRN_SUCCESS) { return rc; }
9513
9514 rc = grn_obj_close(ctx, obj);
9515 if (rc != GRN_SUCCESS) { return rc; }
9516
9517 if (path) {
9518 rc = grn_pat_remove(ctx, path);
9519 if (rc != GRN_SUCCESS) { return rc; }
9520 rc = _grn_obj_remove_spec(ctx, db, id, type);
9521 if (rc != GRN_SUCCESS) { return rc; }
9522 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9523 if (rc != GRN_SUCCESS) { return rc; }
9524 }
9525
9526 grn_obj_touch(ctx, db, NULL);
9527
9528 return rc;
9529}
9530
9531static grn_rc
9532_grn_obj_remove_dat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9533 const char *path, grn_bool dependent)
9534{
9535 grn_rc rc = GRN_SUCCESS;
9536 uint8_t type;
9537
9538 type = obj->header.type;
9539
9540 if (dependent) {
9541 rc = remove_reference_tables(ctx, obj, db);
9542 if (rc != GRN_SUCCESS) {
9543 return rc;
9544 }
9545 } else {
9546 if (!is_removable_table(ctx, obj, db)) {
9547 return ctx->rc;
9548 }
9549 }
9550
9551 rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
9552 if (rc != GRN_SUCCESS) { return rc; }
9553 rc = remove_columns(ctx, obj);
9554 if (rc != GRN_SUCCESS) { return rc; }
9555
9556 rc = grn_obj_close(ctx, obj);
9557 if (rc != GRN_SUCCESS) { return rc; }
9558
9559 if (path) {
9560 rc = grn_dat_remove(ctx, path);
9561 if (rc != GRN_SUCCESS) { return rc; }
9562 rc = _grn_obj_remove_spec(ctx, db, id, type);
9563 if (rc != GRN_SUCCESS) { return rc; }
9564 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9565 if (rc != GRN_SUCCESS) { return rc; }
9566 }
9567
9568 grn_obj_touch(ctx, db, NULL);
9569
9570 return rc;
9571}
9572
9573static grn_rc
9574_grn_obj_remove_hash(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9575 const char *path, grn_bool dependent)
9576{
9577 grn_rc rc = GRN_SUCCESS;
9578 uint8_t type;
9579
9580 type = obj->header.type;
9581
9582 if (dependent) {
9583 rc = remove_reference_tables(ctx, obj, db);
9584 if (rc != GRN_SUCCESS) {
9585 return rc;
9586 }
9587 } else {
9588 if (!is_removable_table(ctx, obj, db)) {
9589 return ctx->rc;
9590 }
9591 }
9592
9593 rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
9594 if (rc != GRN_SUCCESS) { return rc; }
9595 rc = remove_columns(ctx, obj);
9596 if (rc != GRN_SUCCESS) { return rc; }
9597
9598 rc = grn_obj_close(ctx, obj);
9599 if (rc != GRN_SUCCESS) { return rc; }
9600
9601 if (path) {
9602 rc = grn_hash_remove(ctx, path);
9603 if (rc != GRN_SUCCESS) { return rc; }
9604 rc = _grn_obj_remove_spec(ctx, db, id, type);
9605 if (rc != GRN_SUCCESS) { return rc; }
9606 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9607 if (rc != GRN_SUCCESS) { return rc; }
9608 }
9609
9610 grn_obj_touch(ctx, db, NULL);
9611
9612 return rc;
9613}
9614
9615static grn_rc
9616_grn_obj_remove_array(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9617 const char *path, grn_bool dependent)
9618{
9619 grn_rc rc = GRN_SUCCESS;
9620 uint8_t type;
9621
9622 type = obj->header.type;
9623
9624 if (dependent) {
9625 rc = remove_reference_tables(ctx, obj, db);
9626 if (rc != GRN_SUCCESS) {
9627 return rc;
9628 }
9629 } else {
9630 if (!is_removable_table(ctx, obj, db)) {
9631 return ctx->rc;
9632 }
9633 }
9634
9635 rc = remove_columns(ctx, obj);
9636 if (rc != GRN_SUCCESS) { return rc; }
9637
9638 rc = grn_obj_close(ctx, obj);
9639 if (rc != GRN_SUCCESS) { return rc; }
9640
9641 if (path) {
9642 rc = grn_array_remove(ctx, path);
9643 if (rc != GRN_SUCCESS) { return rc; }
9644 rc = _grn_obj_remove_spec(ctx, db, id, type);
9645 if (rc != GRN_SUCCESS) { return rc; }
9646 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9647 if (rc != GRN_SUCCESS) { return rc; }
9648 }
9649
9650 grn_obj_touch(ctx, db, NULL);
9651
9652 return rc;
9653}
9654
9655static grn_rc
9656_grn_obj_remove_ja(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9657 const char *path)
9658{
9659 grn_rc rc = GRN_SUCCESS;
9660 uint8_t type;
9661
9662 type = obj->header.type;
9663
9664 rc = remove_index(ctx, obj, GRN_HOOK_SET);
9665 if (rc != GRN_SUCCESS) { return rc; }
9666 rc = grn_obj_close(ctx, obj);
9667 if (rc != GRN_SUCCESS) { return rc; }
9668
9669 if (path) {
9670 rc = grn_ja_remove(ctx, path);
9671 if (rc != GRN_SUCCESS) { return rc; }
9672 rc = _grn_obj_remove_spec(ctx, db, id, type);
9673 if (rc != GRN_SUCCESS) { return rc; }
9674 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9675 if (rc != GRN_SUCCESS) { return rc; }
9676 }
9677
9678 grn_obj_touch(ctx, db, NULL);
9679
9680 return rc;
9681}
9682
9683static grn_rc
9684_grn_obj_remove_ra(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9685 const char *path)
9686{
9687 grn_rc rc = GRN_SUCCESS;
9688 uint8_t type;
9689
9690 type = obj->header.type;
9691
9692 rc = remove_index(ctx, obj, GRN_HOOK_SET);
9693 if (rc != GRN_SUCCESS) { return rc; }
9694 rc = grn_obj_close(ctx, obj);
9695 if (rc != GRN_SUCCESS) { return rc; }
9696
9697 if (path) {
9698 rc = grn_ra_remove(ctx, path);
9699 if (rc != GRN_SUCCESS) { return rc; }
9700 rc = _grn_obj_remove_spec(ctx, db, id, type);
9701 if (rc != GRN_SUCCESS) { return rc; }
9702 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9703 if (rc != GRN_SUCCESS) { return rc; }
9704 }
9705 grn_obj_touch(ctx, db, NULL);
9706
9707 return rc;
9708}
9709
9710static grn_rc
9711_grn_obj_remove_index(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9712 const char *path)
9713{
9714 grn_rc rc = GRN_SUCCESS;
9715 uint8_t type;
9716
9717 type = obj->header.type;
9718
9719 delete_source_hook(ctx, obj);
9720 rc = grn_obj_close(ctx, obj);
9721 if (rc != GRN_SUCCESS) { return rc; }
9722
9723 if (path) {
9724 rc = grn_ii_remove(ctx, path);
9725 if (rc != GRN_SUCCESS) { return rc; }
9726 rc = _grn_obj_remove_spec(ctx, db, id, type);
9727 if (rc != GRN_SUCCESS) { return rc; }
9728 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9729 if (rc != GRN_SUCCESS) { return rc; }
9730 }
9731
9732 grn_obj_touch(ctx, db, NULL);
9733
9734 return rc;
9735}
9736
9737static grn_rc
9738_grn_obj_remove_db_obj(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9739 const char *path)
9740{
9741 grn_rc rc = GRN_SUCCESS;
9742 uint8_t type;
9743
9744 type = obj->header.type;
9745
9746 rc = grn_obj_close(ctx, obj);
9747 if (rc != GRN_SUCCESS) { return rc; }
9748
9749 if (path) {
9750 rc = grn_io_remove(ctx, path);
9751 if (rc != GRN_SUCCESS) { return rc; }
9752 }
9753
9754 if (!(id & GRN_OBJ_TMP_OBJECT)) {
9755 rc = _grn_obj_remove_spec(ctx, db, id, type);
9756 if (rc != GRN_SUCCESS) { return rc; }
9757 rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9758 if (rc != GRN_SUCCESS) { return rc; }
9759 }
9760
9761 grn_obj_touch(ctx, db, NULL);
9762
9763 return rc;
9764}
9765
9766static grn_rc
9767_grn_obj_remove_other(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
9768 const char *path)
9769{
9770 return grn_obj_close(ctx, obj);
9771}
9772
9773static grn_rc
9774_grn_obj_remove(grn_ctx *ctx, grn_obj *obj, grn_bool dependent)
9775{
9776 grn_rc rc = GRN_SUCCESS;
9777 grn_id id = GRN_ID_NIL;
9778 grn_obj *db = NULL;
9779 const char *io_path;
9780 char *path;
9781 grn_bool is_temporary_open_target = GRN_FALSE;
9782
9783 if (ctx->impl && ctx->impl->db) {
9784 grn_id id;
9785 uint32_t s = 0;
9786 const char *n;
9787
9788 id = DB_OBJ(obj)->id;
9789 n = _grn_table_key(ctx, ctx->impl->db, id, &s);
9790 if (s > 0) {
9791 GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:%u:obj_remove %.*s", id, s, n);
9792 }
9793 }
9794 if (obj->header.type != GRN_PROC &&
9795 (io_path = grn_obj_path(ctx, obj)) && *io_path != '\0') {
9796 if (!(path = GRN_STRDUP(io_path))) {
9797 ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
9798 return ctx->rc;
9799 }
9800 } else {
9801 path = NULL;
9802 }
9803 if (GRN_DB_OBJP(obj)) {
9804 id = DB_OBJ(obj)->id;
9805 db = DB_OBJ(obj)->db;
9806 }
9807 switch (obj->header.type) {
9808 case GRN_DB :
9809 rc = _grn_obj_remove_db(ctx, obj, db, id, path);
9810 break;
9811 case GRN_TABLE_PAT_KEY :
9812 rc = _grn_obj_remove_pat(ctx, obj, db, id, path, dependent);
9813 is_temporary_open_target = GRN_TRUE;
9814 break;
9815 case GRN_TABLE_DAT_KEY :
9816 rc = _grn_obj_remove_dat(ctx, obj, db, id, path, dependent);
9817 is_temporary_open_target = GRN_TRUE;
9818 break;
9819 case GRN_TABLE_HASH_KEY :
9820 rc = _grn_obj_remove_hash(ctx, obj, db, id, path, dependent);
9821 is_temporary_open_target = GRN_TRUE;
9822 break;
9823 case GRN_TABLE_NO_KEY :
9824 rc = _grn_obj_remove_array(ctx, obj, db, id, path, dependent);
9825 is_temporary_open_target = GRN_TRUE;
9826 break;
9827 case GRN_COLUMN_VAR_SIZE :
9828 rc = _grn_obj_remove_ja(ctx, obj, db, id, path);
9829 is_temporary_open_target = GRN_TRUE;
9830 break;
9831 case GRN_COLUMN_FIX_SIZE :
9832 rc = _grn_obj_remove_ra(ctx, obj, db, id, path);
9833 is_temporary_open_target = GRN_TRUE;
9834 break;
9835 case GRN_COLUMN_INDEX :
9836 rc = _grn_obj_remove_index(ctx, obj, db, id, path);
9837 is_temporary_open_target = GRN_TRUE;
9838 break;
9839 default :
9840 if (GRN_DB_OBJP(obj)) {
9841 rc = _grn_obj_remove_db_obj(ctx, obj, db, id, path);
9842 } else {
9843 rc = _grn_obj_remove_other(ctx, obj, db, id, path);
9844 }
9845 }
9846 if (path) {
9847 GRN_FREE(path);
9848 } else {
9849 is_temporary_open_target = GRN_FALSE;
9850 }
9851
9852 if (is_temporary_open_target && rc == GRN_SUCCESS) {
9853 grn_obj *space;
9854 space = ctx->impl->temporary_open_spaces.current;
9855 if (space) {
9856 unsigned int i, n_elements;
9857 n_elements = GRN_BULK_VSIZE(space) / sizeof(grn_obj *);
9858 for (i = 0; i < n_elements; i++) {
9859 if (GRN_PTR_VALUE_AT(space, i) == obj) {
9860 GRN_PTR_SET_AT(ctx, space, i, NULL);
9861 }
9862 }
9863 }
9864 }
9865
9866 return rc;
9867}
9868
9869grn_rc
9870grn_obj_remove(grn_ctx *ctx, grn_obj *obj)
9871{
9872 grn_rc rc = GRN_SUCCESS;
9873 GRN_API_ENTER;
9874 if (ctx->impl && ctx->impl->db && ctx->impl->db != obj) {
9875 grn_io *io = grn_obj_get_io(ctx, ctx->impl->db);
9876 rc = grn_io_lock(ctx, io, grn_lock_timeout);
9877 if (rc == GRN_SUCCESS) {
9878 rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9879 grn_io_unlock(io);
9880 }
9881 } else {
9882 rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
9883 }
9884 GRN_API_RETURN(rc);
9885}
9886
9887grn_rc
9888grn_obj_remove_dependent(grn_ctx *ctx, grn_obj *obj)
9889{
9890 grn_rc rc = GRN_SUCCESS;
9891 GRN_API_ENTER;
9892 if (ctx->impl && ctx->impl->db && ctx->impl->db != obj) {
9893 grn_io *io = grn_obj_get_io(ctx, ctx->impl->db);
9894 rc = grn_io_lock(ctx, io, grn_lock_timeout);
9895 if (rc == GRN_SUCCESS) {
9896 rc = _grn_obj_remove(ctx, obj, GRN_TRUE);
9897 grn_io_unlock(io);
9898 }
9899 } else {
9900 rc = _grn_obj_remove(ctx, obj, GRN_TRUE);
9901 }
9902 GRN_API_RETURN(rc);
9903}
9904
9905grn_rc
9906grn_obj_remove_force(grn_ctx *ctx, const char *name, int name_size)
9907{
9908 grn_rc rc = GRN_SUCCESS;
9909 grn_obj *db;
9910 grn_id obj_id;
9911 char path[PATH_MAX];
9912
9913 GRN_API_ENTER;
9914
9915 if (!(ctx->impl && ctx->impl->db)) {
9916 ERR(GRN_INVALID_ARGUMENT,
9917 "[object][remove][force] database isn't initialized");
9918 rc = ctx->rc;
9919 goto exit;
9920 }
9921
9922 db = ctx->impl->db;
9923 if (name_size == -1) {
9924 name_size = strlen(name);
9925 }
9926 obj_id = grn_table_get(ctx, db, name, name_size);
9927 if (obj_id == GRN_ID_NIL) {
9928 ERR(GRN_INVALID_ARGUMENT,
9929 "[object][remove][force] nonexistent object: <%.*s>",
9930 name_size, name);
9931 rc = ctx->rc;
9932 goto exit;
9933 }
9934
9935 grn_obj_delete_by_id(ctx, db, obj_id, GRN_TRUE);
9936 grn_obj_path_by_id(ctx, db, obj_id, path);
9937 grn_io_remove_if_exist(ctx, path);
9938 grn_strcat(path, PATH_MAX, ".c");
9939 grn_io_remove_if_exist(ctx, path);
9940
9941exit :
9942 GRN_API_RETURN(rc);
9943}
9944
9945grn_rc
9946grn_table_update_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
9947 const void *dest_key, unsigned int dest_key_size)
9948{
9949 grn_rc rc = GRN_OPERATION_NOT_SUPPORTED;
9950 GRN_API_ENTER;
9951 if (table->header.type == GRN_TABLE_DAT_KEY) {
9952 grn_dat *dat = (grn_dat *)table;
9953 if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
9954 if (grn_io_lock(ctx, dat->io, grn_lock_timeout)) {
9955 rc = ctx->rc;
9956 } else {
9957 rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
9958 grn_io_unlock(dat->io);
9959 }
9960 } else {
9961 rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
9962 }
9963 }
9964 GRN_API_RETURN(rc);
9965}
9966
9967grn_rc
9968grn_table_update(grn_ctx *ctx, grn_obj *table,
9969 const void *src_key, unsigned int src_key_size,
9970 const void *dest_key, unsigned int dest_key_size)
9971{
9972 grn_rc rc = GRN_OPERATION_NOT_SUPPORTED;
9973 GRN_API_ENTER;
9974 if (table->header.type == GRN_TABLE_DAT_KEY) {
9975 rc = grn_dat_update(ctx, (grn_dat *)table,
9976 src_key, src_key_size,
9977 dest_key, dest_key_size);
9978 }
9979 GRN_API_RETURN(rc);
9980}
9981
9982grn_rc
9983grn_obj_rename(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
9984{
9985 grn_rc rc = GRN_INVALID_ARGUMENT;
9986 GRN_API_ENTER;
9987 if (ctx && ctx->impl && GRN_DB_P(ctx->impl->db) && GRN_DB_OBJP(obj) && !IS_TEMP(obj)) {
9988 grn_db *s = (grn_db *)ctx->impl->db;
9989 grn_obj *keys = (grn_obj *)s->keys;
9990 rc = grn_table_update_by_id(ctx, keys, DB_OBJ(obj)->id, name, name_size);
9991 }
9992 GRN_API_RETURN(rc);
9993}
9994
9995grn_rc
9996grn_table_rename(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
9997{
9998 grn_rc rc = GRN_INVALID_ARGUMENT;
9999 grn_hash *cols;
10000
10001 GRN_API_ENTER;
10002
10003 if (!GRN_OBJ_TABLEP(table)) {
10004 char table_name[GRN_TABLE_MAX_KEY_SIZE];
10005 int table_name_size;
10006 table_name_size = grn_obj_name(ctx, table, table_name,
10007 GRN_TABLE_MAX_KEY_SIZE);
10008 rc = GRN_INVALID_ARGUMENT;
10009 ERR(rc,
10010 "[table][rename] isn't table: <%.*s> -> <%.*s>",
10011 table_name_size, table_name,
10012 name_size, name);
10013 goto exit;
10014 }
10015 if (IS_TEMP(table)) {
10016 rc = GRN_INVALID_ARGUMENT;
10017 ERR(rc,
10018 "[table][rename] temporary table doesn't have name: "
10019 "(anonymous) -> <%.*s>",
10020 name_size, name);
10021 goto exit;
10022 }
10023
10024 if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
10025 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
10026 grn_table_columns(ctx, table, "", 0, (grn_obj *)cols);
10027 if (!(rc = grn_obj_rename(ctx, table, name, name_size))) {
10028 grn_id *key;
10029 char fullname[GRN_TABLE_MAX_KEY_SIZE];
10030 grn_memcpy(fullname, name, name_size);
10031 fullname[name_size] = GRN_DB_DELIMITER;
10032 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
10033 grn_obj *col = grn_ctx_at(ctx, *key);
10034 if (col) {
10035 int colname_len = grn_column_name(ctx, col, fullname + name_size + 1,
10036 GRN_TABLE_MAX_KEY_SIZE - name_size - 1);
10037 if (colname_len) {
10038 if ((rc = grn_obj_rename(ctx, col, fullname,
10039 name_size + 1 + colname_len))) {
10040 break;
10041 }
10042 }
10043 }
10044 });
10045 }
10046 grn_hash_close(ctx, cols);
10047 }
10048exit:
10049 GRN_API_RETURN(rc);
10050}
10051
10052grn_rc
10053grn_column_rename(grn_ctx *ctx, grn_obj *column, const char *name, unsigned int name_size)
10054{
10055 grn_rc rc = GRN_INVALID_ARGUMENT;
10056 GRN_API_ENTER;
10057 if (GRN_DB_OBJP(column)) {
10058 char fullname[GRN_TABLE_MAX_KEY_SIZE];
10059 grn_db *s = (grn_db *)DB_OBJ(column)->db;
10060 int len = grn_table_get_key(ctx, s->keys, DB_OBJ(column)->header.domain,
10061 fullname, GRN_TABLE_MAX_KEY_SIZE);
10062 if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
10063 ERR(GRN_INVALID_ARGUMENT,
10064 "[column][rename] too long column name: required name_size(%d) < %d"
10065 ": <%.*s>.<%.*s>",
10066 name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - len,
10067 len, fullname, name_size, name);
10068 goto exit;
10069 }
10070 fullname[len] = GRN_DB_DELIMITER;
10071 grn_memcpy(fullname + len + 1, name, name_size);
10072 name_size += len + 1;
10073 rc = grn_obj_rename(ctx, column, fullname, name_size);
10074 if (rc == GRN_SUCCESS) {
10075 grn_obj_touch(ctx, column, NULL);
10076 }
10077 }
10078exit :
10079 GRN_API_RETURN(rc);
10080}
10081
10082grn_rc
10083grn_obj_path_rename(grn_ctx *ctx, const char *old_path, const char *new_path)
10084{
10085 GRN_API_ENTER;
10086 GRN_API_RETURN(GRN_SUCCESS);
10087}
10088
10089/* db must be validated by caller */
10090grn_id
10091grn_obj_register(grn_ctx *ctx, grn_obj *db, const char *name, unsigned int name_size)
10092{
10093 grn_id id = GRN_ID_NIL;
10094 if (name && name_size) {
10095 grn_db *s = (grn_db *)db;
10096 int added;
10097 if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
10098 grn_rc rc;
10099 rc = ctx->rc;
10100 if (rc == GRN_SUCCESS) {
10101 rc = GRN_NO_MEMORY_AVAILABLE;
10102 }
10103 ERR(rc,
10104 "[object][register] failed to register a name: <%.*s>%s%s%s",
10105 name_size, name,
10106 ctx->rc == GRN_SUCCESS ? "" : ": <",
10107 ctx->rc == GRN_SUCCESS ? "" : ctx->errbuf,
10108 ctx->rc == GRN_SUCCESS ? "" : ">");
10109 } else if (!added) {
10110 ERR(GRN_INVALID_ARGUMENT,
10111 "[object][register] already used name was assigned: <%.*s>",
10112 name_size, name);
10113 id = GRN_ID_NIL;
10114 }
10115 } else if (ctx->impl && ctx->impl->values) {
10116 id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
10117 }
10118 return id;
10119}
10120
10121grn_rc
10122grn_obj_delete_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, grn_bool removep)
10123{
10124 grn_rc rc = GRN_INVALID_ARGUMENT;
10125 GRN_API_ENTER;
10126 if (id) {
10127 if (id & GRN_OBJ_TMP_OBJECT) {
10128 if (ctx->impl) {
10129 if (id & GRN_OBJ_TMP_COLUMN) {
10130 if (ctx->impl->temporary_columns) {
10131 rc = grn_pat_delete_by_id(ctx, ctx->impl->temporary_columns,
10132 id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT),
10133 NULL);
10134 }
10135 } else {
10136 if (ctx->impl->values) {
10137 rc = grn_array_delete_by_id(ctx, ctx->impl->values,
10138 id & ~GRN_OBJ_TMP_OBJECT, NULL);
10139 }
10140 }
10141 }
10142 } else {
10143 db_value *vp;
10144 grn_db *s = (grn_db *)db;
10145 if ((vp = grn_tiny_array_at(&s->values, id))) {
10146 GRN_ASSERT(!vp->lock);
10147 vp->lock = 0;
10148 vp->ptr = NULL;
10149 vp->done = 0;
10150 }
10151 if (removep) {
10152 switch (s->keys->header.type) {
10153 case GRN_TABLE_PAT_KEY :
10154 rc = grn_pat_delete_by_id(ctx, (grn_pat *)s->keys, id, NULL);
10155 break;
10156 case GRN_TABLE_DAT_KEY :
10157 rc = grn_dat_delete_by_id(ctx, (grn_dat *)s->keys, id, NULL);
10158 break;
10159 }
10160 } else {
10161 rc = GRN_SUCCESS;
10162 }
10163 }
10164 }
10165 GRN_API_RETURN(rc);
10166}
10167
10168
10169grn_rc
10170grn_obj_path_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, char *buffer)
10171{
10172 grn_rc rc = GRN_SUCCESS;
10173 GRN_API_ENTER;
10174 if (!GRN_DB_P(db) || !buffer) {
10175 rc = GRN_INVALID_ARGUMENT;
10176 } else {
10177 grn_db_generate_pathname(ctx, db, id, buffer);
10178 }
10179 GRN_API_RETURN(rc);
10180}
10181
10182/* db must be validated by caller */
10183grn_rc
10184grn_db_obj_init(grn_ctx *ctx, grn_obj *db, grn_id id, grn_db_obj *obj)
10185{
10186 grn_rc rc = GRN_SUCCESS;
10187 if (id) {
10188 if (id & GRN_OBJ_TMP_OBJECT) {
10189 if (id & GRN_OBJ_TMP_COLUMN) {
10190 if (ctx->impl && ctx->impl->temporary_columns) {
10191 grn_id real_id = id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT);
10192 rc = grn_pat_set_value(ctx, ctx->impl->temporary_columns,
10193 real_id, &obj, GRN_OBJ_SET);
10194 }
10195 } else {
10196 if (ctx->impl && ctx->impl->values) {
10197 rc = grn_array_set_value(ctx, ctx->impl->values,
10198 id & ~GRN_OBJ_TMP_OBJECT, &obj, GRN_OBJ_SET);
10199 }
10200 }
10201 } else {
10202 db_value *vp;
10203 vp = grn_tiny_array_at(&((grn_db *)db)->values, id);
10204 if (!vp) {
10205 rc = GRN_NO_MEMORY_AVAILABLE;
10206 ERR(rc, "grn_tiny_array_at failed (%d)", id);
10207 return rc;
10208 }
10209 vp->lock = 1;
10210 vp->ptr = (grn_obj *)obj;
10211 }
10212 }
10213 obj->id = id;
10214 obj->db = db;
10215 obj->source = NULL;
10216 obj->source_size = 0;
10217 {
10218 grn_hook_entry entry;
10219 for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
10220 obj->hooks[entry] = NULL;
10221 }
10222 }
10223 grn_obj_spec_save(ctx, obj);
10224 return rc;
10225}
10226
10227#define GET_PATH(spec,decoded_spec,buffer,s,id) do {\
10228 if (spec->header.flags & GRN_OBJ_CUSTOM_NAME) {\
10229 const char *path;\
10230 unsigned int size = grn_vector_get_element(ctx,\
10231 decoded_spec,\
10232 GRN_SERIALIZED_SPEC_INDEX_PATH,\
10233 &path,\
10234 NULL,\
10235 NULL);\
10236 if (size > PATH_MAX) { ERR(GRN_FILENAME_TOO_LONG, "too long path"); }\
10237 grn_memcpy(buffer, path, size);\
10238 buffer[size] = '\0';\
10239 } else {\
10240 grn_db_generate_pathname(ctx, (grn_obj *)s, id, buffer);\
10241 }\
10242} while (0)
10243
10244#define UNPACK_INFO(spec,decoded_spec) do {\
10245 if (vp->ptr) {\
10246 const char *p;\
10247 uint32_t size;\
10248 grn_db_obj *r = DB_OBJ(vp->ptr);\
10249 r->header = spec->header;\
10250 r->id = id;\
10251 r->range = spec->range;\
10252 r->db = (grn_obj *)s;\
10253 size = grn_vector_get_element(ctx,\
10254 decoded_spec,\
10255 GRN_SERIALIZED_SPEC_INDEX_SOURCE,\
10256 &p,\
10257 NULL,\
10258 NULL);\
10259 if (size) {\
10260 if ((r->source = GRN_MALLOC(size))) {\
10261 grn_memcpy(r->source, p, size);\
10262 r->source_size = size;\
10263 }\
10264 }\
10265 size = grn_vector_get_element(ctx,\
10266 decoded_spec,\
10267 GRN_SERIALIZED_SPEC_INDEX_HOOK,\
10268 &p,\
10269 NULL,\
10270 NULL);\
10271 grn_hook_unpack(ctx, r, p, size);\
10272 }\
10273} while (0)
10274
10275static void
10276grn_token_filters_unpack(grn_ctx *ctx,
10277 grn_obj *token_filters,
10278 grn_obj *spec_vector)
10279{
10280 grn_id *token_filter_ids;
10281 unsigned int element_size;
10282 unsigned int i, n_token_filter_ids;
10283
10284 if (grn_vector_size(ctx, spec_vector) <= GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS) {
10285 return;
10286 }
10287
10288 element_size = grn_vector_get_element(ctx,
10289 spec_vector,
10290 GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS,
10291 (const char **)(&token_filter_ids),
10292 NULL,
10293 NULL);
10294 n_token_filter_ids = element_size / sizeof(grn_id);
10295 for (i = 0; i < n_token_filter_ids; i++) {
10296 grn_id token_filter_id = token_filter_ids[i];
10297 grn_obj *token_filter;
10298
10299 token_filter = grn_ctx_at(ctx, token_filter_id);
10300 if (!token_filter) {
10301 ERR(GRN_INVALID_ARGUMENT,
10302 "nonexistent token filter ID: %d", token_filter_id);
10303 return;
10304 }
10305 GRN_PTR_PUT(ctx, token_filters, token_filter);
10306 }
10307}
10308
10309grn_bool
10310grn_db_spec_unpack(grn_ctx *ctx,
10311 grn_id id,
10312 void *encoded_spec,
10313 uint32_t encoded_spec_size,
10314 grn_obj_spec **spec,
10315 grn_obj *decoded_spec,
10316 const char *error_message_tag)
10317{
10318 grn_obj *db;
10319 grn_db *db_raw;
10320 grn_rc rc;
10321 uint32_t spec_size;
10322
10323 db = ctx->impl->db;
10324 db_raw = (grn_db *)db;
10325
10326 rc = grn_vector_decode(ctx,
10327 decoded_spec,
10328 encoded_spec,
10329 encoded_spec_size);
10330 if (rc != GRN_SUCCESS) {
10331 const char *name;
10332 uint32_t name_size;
10333 name = _grn_table_key(ctx, db, id, &name_size);
10334 GRN_LOG((ctx), GRN_LOG_ERROR,
10335 "%s: failed to decode spec: <%u>(<%.*s>):<%u>: %s",
10336 error_message_tag,
10337 id,
10338 name_size, name,
10339 encoded_spec_size,
10340 grn_rc_to_string(rc));
10341 return GRN_FALSE;
10342 }
10343
10344 spec_size = grn_vector_get_element(ctx,
10345 decoded_spec,
10346 GRN_SERIALIZED_SPEC_INDEX_SPEC,
10347 (const char **)spec,
10348 NULL,
10349 NULL);
10350 if (spec_size == 0) {
10351 const char *name;
10352 uint32_t name_size;
10353 name = _grn_table_key(ctx, db, id, &name_size);
10354 GRN_LOG(ctx, GRN_LOG_ERROR,
10355 "%s: spec value is empty: <%u>(<%.*s>)",
10356 error_message_tag,
10357 id,
10358 name_size, name);
10359 return GRN_FALSE;
10360 }
10361
10362 return GRN_TRUE;
10363}
10364
10365grn_obj *
10366grn_ctx_at(grn_ctx *ctx, grn_id id)
10367{
10368 grn_obj *res = NULL;
10369 if (!ctx || !ctx->impl || !id) { return res; }
10370 GRN_API_ENTER;
10371 if (id & GRN_OBJ_TMP_OBJECT) {
10372 if (id & GRN_OBJ_TMP_COLUMN) {
10373 if (ctx->impl->temporary_columns) {
10374 grn_id real_id = id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT);
10375 grn_obj **tmp_obj;
10376 uint32_t size;
10377 tmp_obj = (grn_obj **)grn_pat_get_value_(ctx,
10378 ctx->impl->temporary_columns,
10379 real_id,
10380 &size);
10381 if (tmp_obj) {
10382 res = *tmp_obj;
10383 }
10384 }
10385 } else {
10386 if (ctx->impl->values) {
10387 grn_obj **tmp_obj;
10388 tmp_obj = _grn_array_get_value(ctx, ctx->impl->values,
10389 id & ~GRN_OBJ_TMP_OBJECT);
10390 if (tmp_obj) {
10391 res = *tmp_obj;
10392 }
10393 }
10394 }
10395 } else {
10396 grn_db *s = (grn_db *)ctx->impl->db;
10397 if (s) {
10398 db_value *vp;
10399 uint32_t l, *pl, ntrial;
10400 if (!(vp = grn_tiny_array_at(&s->values, id))) { goto exit; }
10401#ifdef USE_NREF
10402 pl = &vp->lock;
10403 for (ntrial = 0;; ntrial++) {
10404 GRN_ATOMIC_ADD_EX(pl, 1, l);
10405 if (l < GRN_IO_MAX_REF) { break; }
10406 if (ntrial >= 10) {
10407 GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
10408 break;
10409 }
10410 GRN_ATOMIC_ADD_EX(pl, -1, l);
10411 GRN_FUTEX_WAIT(pl);
10412 }
10413#endif /* USE_NREF */
10414 if (s->specs && !vp->ptr /* && !vp->done */) {
10415#ifndef USE_NREF
10416 pl = &vp->lock;
10417 for (ntrial = 0;; ntrial++) {
10418 GRN_ATOMIC_ADD_EX(pl, 1, l);
10419 if (l < GRN_IO_MAX_REF) { break; }
10420 if (ntrial >= 10) {
10421 GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
10422 break;
10423 }
10424 GRN_ATOMIC_ADD_EX(pl, -1, l);
10425 GRN_FUTEX_WAIT(pl);
10426 }
10427#endif /* USE_NREF */
10428 if (!l) {
10429 grn_io_win iw;
10430 uint32_t encoded_spec_size;
10431 void *encoded_spec;
10432
10433 encoded_spec = grn_ja_ref(ctx, s->specs, id, &iw, &encoded_spec_size);
10434 if (encoded_spec) {
10435 grn_bool success;
10436 grn_obj_spec *spec;
10437 grn_obj decoded_spec;
10438
10439 GRN_OBJ_INIT(&decoded_spec, GRN_VECTOR, 0, GRN_DB_TEXT);
10440 success = grn_db_spec_unpack(ctx,
10441 id,
10442 encoded_spec,
10443 encoded_spec_size,
10444 &spec,
10445 &decoded_spec,
10446 "grn_ctx_at");
10447 if (success) {
10448 char buffer[PATH_MAX];
10449 switch (spec->header.type) {
10450 case GRN_TYPE :
10451 vp->ptr = (grn_obj *)grn_type_open(ctx, spec);
10452 UNPACK_INFO(spec, &decoded_spec);
10453 break;
10454 case GRN_TABLE_HASH_KEY :
10455 GET_PATH(spec, &decoded_spec, buffer, s, id);
10456 vp->ptr = (grn_obj *)grn_hash_open(ctx, buffer);
10457 if (vp->ptr) {
10458 grn_hash *hash = (grn_hash *)(vp->ptr);
10459 grn_obj_flags flags = vp->ptr->header.flags;
10460 UNPACK_INFO(spec, &decoded_spec);
10461 vp->ptr->header.flags = flags;
10462 grn_token_filters_unpack(ctx,
10463 &(hash->token_filters),
10464 &decoded_spec);
10465 }
10466 break;
10467 case GRN_TABLE_PAT_KEY :
10468 GET_PATH(spec, &decoded_spec, buffer, s, id);
10469 vp->ptr = (grn_obj *)grn_pat_open(ctx, buffer);
10470 if (vp->ptr) {
10471 grn_pat *pat = (grn_pat *)(vp->ptr);
10472 grn_obj_flags flags = vp->ptr->header.flags;
10473 UNPACK_INFO(spec, &decoded_spec);
10474 vp->ptr->header.flags = flags;
10475 grn_token_filters_unpack(ctx,
10476 &(pat->token_filters),
10477 &decoded_spec);
10478 }
10479 break;
10480 case GRN_TABLE_DAT_KEY :
10481 GET_PATH(spec, &decoded_spec, buffer, s, id);
10482 vp->ptr = (grn_obj *)grn_dat_open(ctx, buffer);
10483 if (vp->ptr) {
10484 grn_dat *dat = (grn_dat *)(vp->ptr);
10485 grn_obj_flags flags = vp->ptr->header.flags;
10486 UNPACK_INFO(spec, &decoded_spec);
10487 vp->ptr->header.flags = flags;
10488 grn_token_filters_unpack(ctx,
10489 &(dat->token_filters),
10490 &decoded_spec);
10491 }
10492 break;
10493 case GRN_TABLE_NO_KEY :
10494 GET_PATH(spec, &decoded_spec, buffer, s, id);
10495 vp->ptr = (grn_obj *)grn_array_open(ctx, buffer);
10496 UNPACK_INFO(spec, &decoded_spec);
10497 break;
10498 case GRN_COLUMN_VAR_SIZE :
10499 GET_PATH(spec, &decoded_spec, buffer, s, id);
10500 vp->ptr = (grn_obj *)grn_ja_open(ctx, buffer);
10501 UNPACK_INFO(spec, &decoded_spec);
10502 break;
10503 case GRN_COLUMN_FIX_SIZE :
10504 GET_PATH(spec, &decoded_spec, buffer, s, id);
10505 vp->ptr = (grn_obj *)grn_ra_open(ctx, buffer);
10506 UNPACK_INFO(spec, &decoded_spec);
10507 break;
10508 case GRN_COLUMN_INDEX :
10509 GET_PATH(spec, &decoded_spec, buffer, s, id);
10510 {
10511 grn_obj *table = grn_ctx_at(ctx, spec->header.domain);
10512 vp->ptr = (grn_obj *)grn_ii_open(ctx, buffer, table);
10513 }
10514 UNPACK_INFO(spec, &decoded_spec);
10515 break;
10516 case GRN_PROC :
10517 GET_PATH(spec, &decoded_spec, buffer, s, id);
10518 grn_plugin_register(ctx, buffer);
10519 break;
10520 case GRN_EXPR :
10521 {
10522 const char *p;
10523 uint32_t size;
10524 uint8_t *u;
10525 size = grn_vector_get_element(ctx,
10526 &decoded_spec,
10527 GRN_SERIALIZED_SPEC_INDEX_EXPR,
10528 &p,
10529 NULL,
10530 NULL);
10531 u = (uint8_t *)p;
10532 vp->ptr = grn_expr_open(ctx, spec, u, u + size);
10533 }
10534 break;
10535 }
10536 if (!vp->ptr) {
10537 const char *name;
10538 uint32_t name_size = 0;
10539 name = _grn_table_key(ctx, (grn_obj *)s, id, &name_size);
10540 GRN_LOG(ctx, GRN_LOG_ERROR,
10541 "grn_ctx_at: failed to open object: "
10542 "<%u>(<%.*s>):<%u>(<%s>)",
10543 id,
10544 name_size, name,
10545 spec->header.type,
10546 grn_obj_type_to_string(spec->header.type));
10547 }
10548 }
10549 GRN_OBJ_FIN(ctx, &decoded_spec);
10550 grn_ja_unref(ctx, &iw);
10551 }
10552#ifndef USE_NREF
10553 GRN_ATOMIC_ADD_EX(pl, -1, l);
10554#endif /* USE_NREF */
10555 vp->done = 1;
10556 GRN_FUTEX_WAKE(&vp->ptr);
10557 } else {
10558 for (ntrial = 0; !vp->ptr; ntrial++) {
10559 if (ntrial >= 1000) {
10560 GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%d,%p,%d)!", id, vp->ptr, vp->lock);
10561 break;
10562 }
10563 GRN_FUTEX_WAIT(&vp->ptr);
10564 }
10565 }
10566 if (vp->ptr) {
10567 switch (vp->ptr->header.type) {
10568 case GRN_TABLE_HASH_KEY :
10569 case GRN_TABLE_PAT_KEY :
10570 case GRN_TABLE_DAT_KEY :
10571 case GRN_TABLE_NO_KEY :
10572 case GRN_COLUMN_FIX_SIZE :
10573 case GRN_COLUMN_VAR_SIZE :
10574 case GRN_COLUMN_INDEX :
10575 {
10576 grn_obj *space;
10577 space = ctx->impl->temporary_open_spaces.current;
10578 if (space) {
10579 GRN_PTR_PUT(ctx, space, vp->ptr);
10580 }
10581 }
10582 break;
10583 }
10584 }
10585 }
10586 res = vp->ptr;
10587 if (res && res->header.type == GRN_PROC) {
10588 grn_plugin_ensure_registered(ctx, res);
10589 }
10590 }
10591 }
10592exit :
10593 GRN_API_RETURN(res);
10594}
10595
10596grn_bool
10597grn_ctx_is_opened(grn_ctx *ctx, grn_id id)
10598{
10599 grn_bool is_opened = GRN_FALSE;
10600
10601 if (!ctx || !ctx->impl || !id) {
10602 return GRN_FALSE;
10603 }
10604
10605 GRN_API_ENTER;
10606 if (id & GRN_OBJ_TMP_OBJECT) {
10607 if (ctx->impl->values) {
10608 grn_obj **tmp_obj;
10609 tmp_obj = _grn_array_get_value(ctx, ctx->impl->values,
10610 id & ~GRN_OBJ_TMP_OBJECT);
10611 if (tmp_obj) {
10612 is_opened = GRN_TRUE;
10613 }
10614 }
10615 } else {
10616 grn_db *s = (grn_db *)ctx->impl->db;
10617 if (s) {
10618 db_value *vp;
10619 vp = grn_tiny_array_at(&s->values, id);
10620 if (vp && vp->ptr) {
10621 is_opened = GRN_TRUE;
10622 }
10623 }
10624 }
10625 GRN_API_RETURN(is_opened);
10626}
10627
10628grn_obj *
10629grn_obj_open(grn_ctx *ctx, unsigned char type, grn_obj_flags flags, grn_id domain)
10630{
10631 grn_obj *obj = GRN_MALLOCN(grn_obj, 1);
10632 if (obj) {
10633 GRN_OBJ_INIT(obj, type, flags, domain);
10634 obj->header.impl_flags |= GRN_OBJ_ALLOCATED;
10635 }
10636 return obj;
10637}
10638
10639grn_obj *
10640grn_obj_graft(grn_ctx *ctx, grn_obj *obj)
10641{
10642 grn_obj *new = grn_obj_open(ctx, obj->header.type, obj->header.impl_flags, obj->header.domain);
10643 if (new) {
10644 /* todo : deep copy if (obj->header.impl_flags & GRN_OBJ_DO_SHALLOW_COPY) */
10645 new->u.b.head = obj->u.b.head;
10646 new->u.b.curr = obj->u.b.curr;
10647 new->u.b.tail = obj->u.b.tail;
10648 obj->u.b.head = NULL;
10649 obj->u.b.curr = NULL;
10650 obj->u.b.tail = NULL;
10651 }
10652 return new;
10653}
10654
10655grn_rc
10656grn_pvector_fin(grn_ctx *ctx, grn_obj *obj)
10657{
10658 grn_rc rc;
10659 if (obj->header.impl_flags & GRN_OBJ_OWN) {
10660 /*
10661 * Note that GRN_OBJ_OWN should not be used outside the DB API function
10662 * because grn_obj_close is a DB API function.
10663 */
10664 unsigned int i, n_elements;
10665 n_elements = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
10666 for (i = 0; i < n_elements; i++) {
10667 grn_obj *element = GRN_PTR_VALUE_AT(obj, n_elements - i - 1);
10668 if (element) {
10669 grn_obj_close(ctx, element);
10670 }
10671 }
10672 }
10673 obj->header.type = GRN_VOID;
10674 rc = grn_bulk_fin(ctx, obj);
10675 if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) {
10676 GRN_FREE(obj);
10677 }
10678 return rc;
10679}
10680
10681static void
10682grn_table_close_columns(grn_ctx *ctx, grn_obj *table)
10683{
10684 grn_hash *columns;
10685 int n_columns;
10686
10687 columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
10688 GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
10689 if (!columns) {
10690 return;
10691 }
10692
10693 n_columns = grn_table_columns(ctx, table, "", 0, (grn_obj *)columns);
10694 if (n_columns > 0) {
10695 grn_hash_cursor *cursor;
10696 cursor = grn_hash_cursor_open(ctx, columns, NULL, 0, NULL, 0, 0, -1, 0);
10697 if (cursor) {
10698 while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
10699 grn_id *id;
10700 grn_obj *column;
10701
10702 grn_hash_cursor_get_key(ctx, cursor, (void **)&id);
10703 column = grn_ctx_at(ctx, *id);
10704 if (column) {
10705 grn_obj_close(ctx, column);
10706 }
10707 }
10708 grn_hash_cursor_close(ctx, cursor);
10709 }
10710 }
10711
10712 grn_hash_close(ctx, columns);
10713}
10714
10715grn_rc
10716grn_obj_close(grn_ctx *ctx, grn_obj *obj)
10717{
10718 grn_rc rc = GRN_INVALID_ARGUMENT;
10719 GRN_API_ENTER;
10720 if (obj) {
10721 if (grn_obj_is_table(ctx, obj) &&
10722 (DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)) {
10723 grn_table_close_columns(ctx, obj);
10724 }
10725 if (GRN_DB_OBJP(obj)) {
10726 grn_hook_entry entry;
10727 if (DB_OBJ(obj)->finalizer) {
10728 DB_OBJ(obj)->finalizer(ctx, 1, &obj, &DB_OBJ(obj)->user_data);
10729 }
10730 if (DB_OBJ(obj)->source) {
10731 GRN_FREE(DB_OBJ(obj)->source);
10732 }
10733 for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
10734 grn_hook_free(ctx, DB_OBJ(obj)->hooks[entry]);
10735 }
10736 grn_obj_delete_by_id(ctx, DB_OBJ(obj)->db, DB_OBJ(obj)->id, GRN_FALSE);
10737 }
10738 switch (obj->header.type) {
10739 case GRN_VECTOR :
10740 if (obj->u.v.body && !(obj->header.impl_flags & GRN_OBJ_REFER)) {
10741 grn_obj_close(ctx, obj->u.v.body);
10742 }
10743 if (obj->u.v.sections) { GRN_FREE(obj->u.v.sections); }
10744 if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
10745 rc = GRN_SUCCESS;
10746 break;
10747 case GRN_VOID :
10748 case GRN_BULK :
10749 case GRN_UVECTOR :
10750 case GRN_MSG :
10751 obj->header.type = GRN_VOID;
10752 rc = grn_bulk_fin(ctx, obj);
10753 if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
10754 break;
10755 case GRN_PTR :
10756 if (obj->header.impl_flags & GRN_OBJ_OWN) {
10757 if (GRN_BULK_VSIZE(obj) == sizeof(grn_obj *)) {
10758 grn_obj_close(ctx, GRN_PTR_VALUE(obj));
10759 }
10760 }
10761 obj->header.type = GRN_VOID;
10762 rc = grn_bulk_fin(ctx, obj);
10763 if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
10764 break;
10765 case GRN_PVECTOR :
10766 rc = grn_pvector_fin(ctx, obj);
10767 break;
10768 case GRN_ACCESSOR :
10769 {
10770 grn_accessor *p, *n;
10771 for (p = (grn_accessor *)obj; p; p = n) {
10772 n = p->next;
10773 GRN_FREE(p);
10774 }
10775 }
10776 rc = GRN_SUCCESS;
10777 break;
10778 case GRN_SNIP :
10779 rc = grn_snip_close(ctx, (grn_snip *)obj);
10780 break;
10781 case GRN_STRING :
10782 rc = grn_string_close(ctx, obj);
10783 break;
10784 case GRN_CURSOR_TABLE_PAT_KEY :
10785 grn_pat_cursor_close(ctx, (grn_pat_cursor *)obj);
10786 break;
10787 case GRN_CURSOR_TABLE_DAT_KEY :
10788 grn_dat_cursor_close(ctx, (grn_dat_cursor *)obj);
10789 break;
10790 case GRN_CURSOR_TABLE_HASH_KEY :
10791 grn_hash_cursor_close(ctx, (grn_hash_cursor *)obj);
10792 break;
10793 case GRN_CURSOR_TABLE_NO_KEY :
10794 grn_array_cursor_close(ctx, (grn_array_cursor *)obj);
10795 break;
10796 case GRN_CURSOR_COLUMN_INDEX :
10797 {
10798 grn_index_cursor *ic = (grn_index_cursor *)obj;
10799 if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
10800 GRN_FREE(ic);
10801 }
10802 break;
10803 case GRN_CURSOR_COLUMN_GEO_INDEX :
10804 grn_geo_cursor_close(ctx, obj);
10805 break;
10806 case GRN_CURSOR_CONFIG :
10807 grn_config_cursor_close(ctx, (grn_config_cursor *)obj);
10808 break;
10809 case GRN_TYPE :
10810 GRN_FREE(obj);
10811 rc = GRN_SUCCESS;
10812 break;
10813 case GRN_DB :
10814 rc = grn_db_close(ctx, obj);
10815 break;
10816 case GRN_TABLE_PAT_KEY :
10817 rc = grn_pat_close(ctx, (grn_pat *)obj);
10818 break;
10819 case GRN_TABLE_DAT_KEY :
10820 rc = grn_dat_close(ctx, (grn_dat *)obj);
10821 break;
10822 case GRN_TABLE_HASH_KEY :
10823 rc = grn_hash_close(ctx, (grn_hash *)obj);
10824 break;
10825 case GRN_TABLE_NO_KEY :
10826 rc = grn_array_close(ctx, (grn_array *)obj);
10827 break;
10828 case GRN_COLUMN_VAR_SIZE :
10829 rc = grn_ja_close(ctx, (grn_ja *)obj);
10830 break;
10831 case GRN_COLUMN_FIX_SIZE :
10832 rc = grn_ra_close(ctx, (grn_ra *)obj);
10833 break;
10834 case GRN_COLUMN_INDEX :
10835 rc = grn_ii_close(ctx, (grn_ii *)obj);
10836 break;
10837 case GRN_PROC :
10838 {
10839 uint32_t i;
10840 grn_proc *p = (grn_proc *)obj;
10841 /*
10842 if (obj->header.domain) {
10843 grn_hash_delete(ctx, ctx->impl->qe, &obj->header.domain, sizeof(grn_id), NULL);
10844 }
10845 */
10846 for (i = 0; i < p->nvars; i++) {
10847 grn_obj_close(ctx, &p->vars[i].value);
10848 }
10849 GRN_REALLOC(p->vars, 0);
10850 grn_obj_close(ctx, &p->name_buf);
10851 if (p->obj.range != GRN_ID_NIL) {
10852 grn_plugin_close(ctx, p->obj.range);
10853 }
10854 GRN_FREE(obj);
10855 rc = GRN_SUCCESS;
10856 }
10857 break;
10858 case GRN_EXPR :
10859 rc = grn_expr_close(ctx, obj);
10860 break;
10861 }
10862 }
10863 GRN_API_RETURN(rc);
10864}
10865
10866void
10867grn_obj_unlink(grn_ctx *ctx, grn_obj *obj)
10868{
10869 if (obj &&
10870 (!GRN_DB_OBJP(obj) ||
10871 (((grn_db_obj *)obj)->id & GRN_OBJ_TMP_OBJECT) ||
10872 (((grn_db_obj *)obj)->id == GRN_ID_NIL) ||
10873 obj->header.type == GRN_DB)) {
10874 grn_obj_close(ctx, obj);
10875 } else if (GRN_DB_OBJP(obj)) {
10876#ifdef USE_NREF
10877 grn_db_obj *dob = DB_OBJ(obj);
10878 grn_db *s = (grn_db *)dob->db;
10879 db_value *vp = grn_tiny_array_at(&s->values, dob->id);
10880 if (vp) {
10881 uint32_t l, *pl = &vp->lock;
10882 if (!vp->lock) {
10883 GRN_LOG(ctx, GRN_LOG_ERROR, "invalid unlink(%p,%d)", obj, vp->lock);
10884 return;
10885 }
10886 GRN_ATOMIC_ADD_EX(pl, -1, l);
10887 if (l == 1) {
10888 GRN_ATOMIC_ADD_EX(pl, GRN_IO_MAX_REF, l);
10889 if (l == GRN_IO_MAX_REF) {
10890#ifdef CALL_FINALIZER
10891 grn_obj_close(ctx, obj);
10892 vp->done = 0;
10893 if (dob->finalizer) {
10894 dob->finalizer(ctx, 1, &obj, &dob->user_data);
10895 dob->finalizer = NULL;
10896 dob->user_data.ptr = NULL;
10897 }
10898#endif /* CALL_FINALIZER */
10899 }
10900 GRN_ATOMIC_ADD_EX(pl, -GRN_IO_MAX_REF, l);
10901 GRN_FUTEX_WAKE(pl);
10902 }
10903 }
10904#endif /* USE_NREF */
10905 }
10906}
10907
10908#define VECTOR_CLEAR(ctx,obj) do {\
10909 if ((obj)->u.v.body && !((obj)->header.impl_flags & GRN_OBJ_REFER)) {\
10910 grn_obj_close((ctx), (obj)->u.v.body);\
10911 }\
10912 if ((obj)->u.v.sections) { GRN_FREE((obj)->u.v.sections); }\
10913 (obj)->header.impl_flags &= ~GRN_OBJ_DO_SHALLOW_COPY;\
10914 (obj)->u.b.head = NULL;\
10915 (obj)->u.b.curr = NULL;\
10916 (obj)->u.b.tail = NULL;\
10917} while (0)
10918
10919static void
10920grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj)
10921{
10922 if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
10923 obj->header.type = GRN_VECTOR;
10924 obj->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
10925}
10926
10927static void
10928grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj)
10929{
10930 if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
10931 obj->header.type = GRN_BULK;
10932 obj->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
10933}
10934
10935grn_rc
10936grn_obj_reinit(grn_ctx *ctx, grn_obj *obj, grn_id domain, unsigned char flags)
10937{
10938 if (!GRN_OBJ_MUTABLE(obj)) {
10939 ERR(GRN_INVALID_ARGUMENT, "invalid obj assigned");
10940 } else {
10941 switch (obj->header.type) {
10942 case GRN_PTR :
10943 if (obj->header.impl_flags & GRN_OBJ_OWN) {
10944 if (GRN_BULK_VSIZE(obj) == sizeof(grn_obj *)) {
10945 grn_obj_close(ctx, GRN_PTR_VALUE(obj));
10946 }
10947 obj->header.impl_flags &= ~GRN_OBJ_OWN;
10948 }
10949 break;
10950 case GRN_PVECTOR :
10951 if (obj->header.impl_flags & GRN_OBJ_OWN) {
10952 unsigned int i, n_elements;
10953 n_elements = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
10954 for (i = 0; i < n_elements; i++) {
10955 grn_obj *element = GRN_PTR_VALUE_AT(obj, i);
10956 grn_obj_close(ctx, element);
10957 }
10958 obj->header.impl_flags &= ~GRN_OBJ_OWN;
10959 }
10960 break;
10961 default :
10962 break;
10963 }
10964
10965 switch (domain) {
10966 case GRN_DB_VOID :
10967 if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
10968 obj->header.type = GRN_VOID;
10969 obj->header.domain = domain;
10970 GRN_BULK_REWIND(obj);
10971 break;
10972 case GRN_DB_OBJECT :
10973 case GRN_DB_BOOL :
10974 case GRN_DB_INT8 :
10975 case GRN_DB_UINT8 :
10976 case GRN_DB_INT16 :
10977 case GRN_DB_UINT16 :
10978 case GRN_DB_INT32 :
10979 case GRN_DB_UINT32 :
10980 case GRN_DB_INT64 :
10981 case GRN_DB_UINT64 :
10982 case GRN_DB_FLOAT :
10983 case GRN_DB_TIME :
10984 case GRN_DB_TOKYO_GEO_POINT :
10985 case GRN_DB_WGS84_GEO_POINT :
10986 if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
10987 obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
10988 obj->header.domain = domain;
10989 GRN_BULK_REWIND(obj);
10990 break;
10991 case GRN_DB_SHORT_TEXT :
10992 case GRN_DB_TEXT :
10993 case GRN_DB_LONG_TEXT :
10994 if (flags & GRN_OBJ_VECTOR) {
10995 if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
10996 obj->header.type = GRN_VECTOR;
10997 if (obj->u.v.body) {
10998 grn_obj_reinit(ctx, obj->u.v.body, domain, 0);
10999 }
11000 obj->u.v.n_sections = 0;
11001 } else {
11002 if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
11003 obj->header.type = GRN_BULK;
11004 }
11005 obj->header.domain = domain;
11006 GRN_BULK_REWIND(obj);
11007 break;
11008 default :
11009 {
11010 grn_obj *d = grn_ctx_at(ctx, domain);
11011 if (!d) {
11012 ERR(GRN_INVALID_ARGUMENT, "invalid domain assigned");
11013 } else {
11014 if (d->header.type == GRN_TYPE && (d->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
11015 if (flags & GRN_OBJ_VECTOR) {
11016 if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
11017 obj->header.type = GRN_VECTOR;
11018 } else {
11019 if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
11020 obj->header.type = GRN_BULK;
11021 }
11022 } else {
11023 if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
11024 obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
11025 }
11026 obj->header.domain = domain;
11027 GRN_BULK_REWIND(obj);
11028 }
11029 }
11030 break;
11031 }
11032 }
11033 return ctx->rc;
11034}
11035
11036grn_rc
11037grn_obj_reinit_for(grn_ctx *ctx, grn_obj *obj, grn_obj *domain_obj)
11038{
11039 grn_id domain = GRN_ID_NIL;
11040 grn_obj_flags flags = 0;
11041
11042 if (!GRN_DB_OBJP(domain_obj) && domain_obj->header.type != GRN_ACCESSOR) {
11043 grn_obj inspected;
11044 GRN_TEXT_INIT(&inspected, 0);
11045 grn_inspect_limited(ctx, &inspected, domain_obj);
11046 ERR(GRN_INVALID_ARGUMENT,
11047 "[reinit] invalid domain object: <%.*s>",
11048 (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
11049 GRN_OBJ_FIN(ctx, &inspected);
11050 return ctx->rc;
11051 }
11052
11053 if (grn_column_is_index(ctx, domain_obj)) {
11054 domain = GRN_DB_UINT32;
11055 } else {
11056 grn_obj_get_range_info(ctx, domain_obj, &domain, &flags);
11057 if (GRN_OBJ_TABLEP(domain_obj) &&
11058 domain_obj->header.type != GRN_TABLE_NO_KEY) {
11059 domain = domain_obj->header.domain;
11060 }
11061 }
11062 return grn_obj_reinit(ctx, obj, domain, flags);
11063}
11064
11065const char *
11066grn_obj_path(grn_ctx *ctx, grn_obj *obj)
11067{
11068 grn_io *io;
11069 const char *path = NULL;
11070 GRN_API_ENTER;
11071 if (obj->header.type == GRN_PROC) {
11072 path = grn_plugin_path(ctx, DB_OBJ(obj)->range);
11073 GRN_API_RETURN(path);
11074 }
11075 io = grn_obj_get_io(ctx, obj);
11076 if (io && !(io->flags & GRN_IO_TEMPORARY)) { path = io->path; }
11077 GRN_API_RETURN(path);
11078}
11079
11080int
11081grn_obj_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
11082{
11083 int len = 0;
11084 GRN_API_ENTER;
11085 if (GRN_DB_OBJP(obj)) {
11086 if (DB_OBJ(obj)->id) {
11087 grn_db *s = (grn_db *)DB_OBJ(obj)->db;
11088 grn_id id = DB_OBJ(obj)->id;
11089 if (id & GRN_OBJ_TMP_OBJECT) {
11090 if (id & GRN_OBJ_TMP_COLUMN) {
11091 grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
11092 len = grn_pat_get_key(ctx, ctx->impl->temporary_columns,
11093 real_id, namebuf, buf_size);
11094 }
11095 } else {
11096 len = grn_table_get_key(ctx, s->keys, id, namebuf, buf_size);
11097 }
11098 }
11099 }
11100 GRN_API_RETURN(len);
11101}
11102
11103int
11104grn_column_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
11105{
11106 int len = 0;
11107 char buf[GRN_TABLE_MAX_KEY_SIZE];
11108 if (!obj) { return len; }
11109 GRN_API_ENTER;
11110 if (GRN_DB_OBJP(obj)) {
11111 grn_id id = DB_OBJ(obj)->id;
11112 if (id & GRN_OBJ_TMP_OBJECT) {
11113 if (id & GRN_OBJ_TMP_COLUMN) {
11114 grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
11115 len = grn_pat_get_key(ctx, ctx->impl->temporary_columns,
11116 real_id, buf, GRN_TABLE_MAX_KEY_SIZE);
11117 }
11118 } else if (id && id < GRN_ID_MAX) {
11119 grn_db *s = (grn_db *)DB_OBJ(obj)->db;
11120 len = grn_table_get_key(ctx, s->keys, id, buf, GRN_TABLE_MAX_KEY_SIZE);
11121 }
11122 if (len) {
11123 int cl;
11124 char *p = buf, *p0 = p, *pe = p + len;
11125 for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
11126 if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
11127 }
11128 len = pe - p0;
11129 if (len && len <= buf_size) {
11130 grn_memcpy(namebuf, p0, len);
11131 }
11132 }
11133 } else if (obj->header.type == GRN_ACCESSOR) {
11134 grn_obj name;
11135 grn_accessor *a;
11136
11137 GRN_TEXT_INIT(&name, 0);
11138
11139#define ADD_DELMITER() do { \
11140 if (GRN_TEXT_LEN(&name) > 0) { \
11141 GRN_TEXT_PUTC(ctx, &name, GRN_DB_DELIMITER); \
11142 } \
11143 } while (GRN_FALSE)
11144
11145 for (a = (grn_accessor *)obj; a; a = a->next) {
11146 switch (a->action) {
11147 case GRN_ACCESSOR_GET_ID :
11148 ADD_DELMITER();
11149 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_ID);
11150 break;
11151 case GRN_ACCESSOR_GET_KEY :
11152 if (!a->next) {
11153 ADD_DELMITER();
11154 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_KEY);
11155 }
11156 break;
11157 case GRN_ACCESSOR_GET_VALUE :
11158 if (!a->next) {
11159 ADD_DELMITER();
11160 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_VALUE);
11161 }
11162 break;
11163 case GRN_ACCESSOR_GET_SCORE :
11164 ADD_DELMITER();
11165 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_SCORE);
11166 break;
11167 case GRN_ACCESSOR_GET_NSUBRECS :
11168 ADD_DELMITER();
11169 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_NSUBRECS);
11170 break;
11171 case GRN_ACCESSOR_GET_MAX :
11172 ADD_DELMITER();
11173 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_MAX);
11174 break;
11175 case GRN_ACCESSOR_GET_MIN :
11176 ADD_DELMITER();
11177 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_MIN);
11178 break;
11179 case GRN_ACCESSOR_GET_SUM :
11180 ADD_DELMITER();
11181 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_SUM);
11182 break;
11183 case GRN_ACCESSOR_GET_AVG :
11184 ADD_DELMITER();
11185 GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_AVG);
11186 break;
11187 case GRN_ACCESSOR_GET_COLUMN_VALUE :
11188 ADD_DELMITER();
11189 {
11190 char column_name[GRN_TABLE_MAX_KEY_SIZE];
11191 int column_name_size;
11192 column_name_size = grn_column_name(ctx, a->obj,
11193 column_name,
11194 GRN_TABLE_MAX_KEY_SIZE);
11195 GRN_TEXT_PUT(ctx, &name, column_name, column_name_size);
11196 }
11197 break;
11198 case GRN_ACCESSOR_GET_DB_OBJ :
11199 case GRN_ACCESSOR_LOOKUP :
11200 case GRN_ACCESSOR_FUNCALL :
11201 break;
11202 }
11203 }
11204#undef ADD_DELIMITER
11205
11206 len = GRN_TEXT_LEN(&name);
11207 if (len > 0 && len <= buf_size) {
11208 grn_memcpy(namebuf, GRN_TEXT_VALUE(&name), len);
11209 }
11210
11211 GRN_OBJ_FIN(ctx, &name);
11212 }
11213 GRN_API_RETURN(len);
11214}
11215
11216grn_rc
11217grn_column_name_(grn_ctx *ctx, grn_obj *obj, grn_obj *buf)
11218{
11219 if (GRN_DB_OBJP(obj)) {
11220 uint32_t len = 0;
11221 const char *p = NULL;
11222 grn_id id = DB_OBJ(obj)->id;
11223 if (id & GRN_OBJ_TMP_OBJECT) {
11224 if (id & GRN_OBJ_TMP_COLUMN) {
11225 grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
11226 p = _grn_pat_key(ctx, ctx->impl->temporary_columns, real_id, &len);
11227 }
11228 } else if (id && id < GRN_ID_MAX) {
11229 grn_db *s = (grn_db *)DB_OBJ(obj)->db;
11230 p = _grn_table_key(ctx, s->keys, id, &len);
11231 }
11232 if (len) {
11233 int cl;
11234 const char *p0 = p, *pe = p + len;
11235 for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
11236 if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
11237 }
11238 GRN_TEXT_PUT(ctx, buf, p0, pe - p0);
11239 }
11240 } else if (obj->header.type == GRN_ACCESSOR) {
11241 grn_accessor *a;
11242 for (a = (grn_accessor *)obj; a; a = a->next) {
11243 switch (a->action) {
11244 case GRN_ACCESSOR_GET_ID :
11245 GRN_TEXT_PUT(ctx, buf, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN);
11246 break;
11247 case GRN_ACCESSOR_GET_KEY :
11248 if (!a->next) {
11249 GRN_TEXT_PUT(ctx, buf, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN);
11250 }
11251 break;
11252 case GRN_ACCESSOR_GET_VALUE :
11253 if (!a->next) {
11254 GRN_TEXT_PUT(ctx, buf,
11255 GRN_COLUMN_NAME_VALUE,
11256 GRN_COLUMN_NAME_VALUE_LEN);
11257 }
11258 break;
11259 case GRN_ACCESSOR_GET_SCORE :
11260 GRN_TEXT_PUT(ctx, buf,
11261 GRN_COLUMN_NAME_SCORE,
11262 GRN_COLUMN_NAME_SCORE_LEN);
11263 break;
11264 case GRN_ACCESSOR_GET_NSUBRECS :
11265 GRN_TEXT_PUT(ctx, buf,
11266 GRN_COLUMN_NAME_NSUBRECS,
11267 GRN_COLUMN_NAME_NSUBRECS_LEN);
11268 break;
11269 case GRN_ACCESSOR_GET_MAX :
11270 GRN_TEXT_PUT(ctx, buf,
11271 GRN_COLUMN_NAME_MAX,
11272 GRN_COLUMN_NAME_MAX_LEN);
11273 break;
11274 case GRN_ACCESSOR_GET_MIN :
11275 GRN_TEXT_PUT(ctx, buf,
11276 GRN_COLUMN_NAME_MIN,
11277 GRN_COLUMN_NAME_MIN_LEN);
11278 break;
11279 case GRN_ACCESSOR_GET_SUM :
11280 GRN_TEXT_PUT(ctx, buf,
11281 GRN_COLUMN_NAME_SUM,
11282 GRN_COLUMN_NAME_SUM_LEN);
11283 break;
11284 case GRN_ACCESSOR_GET_AVG :
11285 GRN_TEXT_PUT(ctx, buf,
11286 GRN_COLUMN_NAME_AVG,
11287 GRN_COLUMN_NAME_AVG_LEN);
11288 break;
11289 case GRN_ACCESSOR_GET_COLUMN_VALUE :
11290 grn_column_name_(ctx, a->obj, buf);
11291 if (a->next) { GRN_TEXT_PUTC(ctx, buf, '.'); }
11292 break;
11293 case GRN_ACCESSOR_GET_DB_OBJ :
11294 case GRN_ACCESSOR_LOOKUP :
11295 case GRN_ACCESSOR_FUNCALL :
11296 break;
11297 }
11298 }
11299 }
11300 return ctx->rc;
11301}
11302
11303int
11304grn_obj_expire(grn_ctx *ctx, grn_obj *obj, int threshold)
11305{
11306 GRN_API_ENTER;
11307 GRN_API_RETURN(0);
11308}
11309
11310int
11311grn_obj_check(grn_ctx *ctx, grn_obj *obj)
11312{
11313 GRN_API_ENTER;
11314 GRN_API_RETURN(0);
11315}
11316
11317grn_rc
11318grn_obj_lock(grn_ctx *ctx, grn_obj *obj, grn_id id, int timeout)
11319{
11320 grn_rc rc = GRN_SUCCESS;
11321 GRN_API_ENTER;
11322 rc = grn_io_lock(ctx, grn_obj_get_io(ctx, obj), timeout);
11323 if (rc == GRN_SUCCESS && obj && obj->header.type == GRN_COLUMN_INDEX) {
11324 rc = grn_io_lock(ctx, ((grn_ii *)obj)->chunk, timeout);
11325 }
11326 GRN_API_RETURN(rc);
11327}
11328
11329grn_rc
11330grn_obj_unlock(grn_ctx *ctx, grn_obj *obj, grn_id id)
11331{
11332 GRN_API_ENTER;
11333 if (obj && obj->header.type == GRN_COLUMN_INDEX) {
11334 grn_io_unlock(((grn_ii *)obj)->chunk);
11335 }
11336 grn_io_unlock(grn_obj_get_io(ctx, obj));
11337 GRN_API_RETURN(GRN_SUCCESS);
11338}
11339
11340grn_user_data *
11341grn_obj_user_data(grn_ctx *ctx, grn_obj *obj)
11342{
11343 if (!GRN_DB_OBJP(obj)) { return NULL; }
11344 return &DB_OBJ(obj)->user_data;
11345}
11346
11347grn_rc
11348grn_obj_set_finalizer(grn_ctx *ctx, grn_obj *obj, grn_proc_func *func)
11349{
11350 if (!GRN_DB_OBJP(obj)) { return GRN_INVALID_ARGUMENT; }
11351 DB_OBJ(obj)->finalizer = func;
11352 return GRN_SUCCESS;
11353}
11354
11355grn_rc
11356grn_obj_clear_lock(grn_ctx *ctx, grn_obj *obj)
11357{
11358 GRN_API_ENTER;
11359 switch (obj->header.type) {
11360 case GRN_DB:
11361 {
11362 grn_table_cursor *cur;
11363 if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
11364 grn_id id;
11365 while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
11366 grn_obj *tbl = grn_ctx_at(ctx, id);
11367 if (tbl) {
11368 switch (tbl->header.type) {
11369 case GRN_TABLE_HASH_KEY :
11370 case GRN_TABLE_PAT_KEY:
11371 case GRN_TABLE_DAT_KEY:
11372 case GRN_TABLE_NO_KEY:
11373 grn_obj_clear_lock(ctx, tbl);
11374 break;
11375 }
11376 } else {
11377 if (ctx->rc != GRN_SUCCESS) {
11378 ERRCLR(ctx);
11379 }
11380 }
11381 }
11382 grn_table_cursor_close(ctx, cur);
11383 }
11384 }
11385 grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11386 {
11387 grn_db *db = (grn_db *)obj;
11388 if (db->specs) {
11389 grn_obj_clear_lock(ctx, (grn_obj *)(db->specs));
11390 }
11391 }
11392 break;
11393 case GRN_TABLE_NO_KEY :
11394 grn_array_queue_lock_clear(ctx, (grn_array *)obj);
11395 /* fallthru */
11396 case GRN_TABLE_HASH_KEY :
11397 case GRN_TABLE_PAT_KEY :
11398 case GRN_TABLE_DAT_KEY :
11399 {
11400 grn_hash *cols;
11401 if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
11402 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
11403 if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
11404 grn_id *key;
11405 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
11406 grn_obj *col = grn_ctx_at(ctx, *key);
11407 if (col) { grn_obj_clear_lock(ctx, col); }
11408 });
11409 }
11410 grn_hash_close(ctx, cols);
11411 }
11412 grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11413 }
11414 break;
11415 case GRN_COLUMN_FIX_SIZE:
11416 case GRN_COLUMN_VAR_SIZE:
11417 grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11418 break;
11419 case GRN_COLUMN_INDEX:
11420 grn_io_clear_lock(grn_obj_get_io(ctx, obj));
11421 if (obj) {
11422 grn_io_clear_lock(((grn_ii *)obj)->chunk);
11423 }
11424 break;
11425 }
11426 GRN_API_RETURN(GRN_SUCCESS);
11427}
11428
11429unsigned int
11430grn_obj_is_locked(grn_ctx *ctx, grn_obj *obj)
11431{
11432 unsigned int res = 0;
11433 GRN_API_ENTER;
11434 res = grn_io_is_locked(grn_obj_get_io(ctx, obj));
11435 if (obj && obj->header.type == GRN_COLUMN_INDEX) {
11436 res += grn_io_is_locked(((grn_ii *)obj)->chunk);
11437 }
11438 GRN_API_RETURN(res);
11439}
11440
11441grn_rc
11442grn_obj_flush(grn_ctx *ctx, grn_obj *obj)
11443{
11444 grn_rc rc = GRN_SUCCESS;
11445
11446 GRN_API_ENTER;
11447
11448 switch (obj->header.type) {
11449 case GRN_DB :
11450 {
11451 grn_db *db = (grn_db *)obj;
11452 rc = grn_obj_flush(ctx, db->keys);
11453 if (rc == GRN_SUCCESS && db->specs) {
11454 rc = grn_obj_flush(ctx, (grn_obj *)(db->specs));
11455 }
11456 if (rc == GRN_SUCCESS) {
11457 rc = grn_obj_flush(ctx, (grn_obj *)(db->config));
11458 }
11459 }
11460 break;
11461 case GRN_TABLE_DAT_KEY :
11462 rc = grn_dat_flush(ctx, (grn_dat *)obj);
11463 break;
11464 case GRN_COLUMN_INDEX :
11465 rc = grn_ii_flush(ctx, (grn_ii *)obj);
11466 break;
11467 default :
11468 {
11469 grn_io *io;
11470 io = grn_obj_get_io(ctx, obj);
11471 if (io) {
11472 rc = grn_io_flush(ctx, io);
11473 }
11474 }
11475 break;
11476 }
11477
11478 if (rc == GRN_SUCCESS &&
11479 GRN_DB_OBJP(obj) &&
11480 DB_OBJ(obj)->id != GRN_ID_NIL &&
11481 !IS_TEMP(obj)) {
11482 rc = grn_db_clean(ctx, DB_OBJ(obj)->db);
11483 }
11484
11485 GRN_API_RETURN(rc);
11486}
11487
11488grn_rc
11489grn_obj_flush_recursive(grn_ctx *ctx, grn_obj *obj)
11490{
11491 grn_rc rc = GRN_SUCCESS;
11492
11493 GRN_API_ENTER;
11494 switch (obj->header.type) {
11495 case GRN_DB :
11496 {
11497 grn_table_cursor *cursor;
11498 grn_id id;
11499
11500 cursor = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0);
11501 if (!cursor) {
11502 GRN_API_RETURN(ctx->rc);
11503 }
11504
11505 while ((id = grn_table_cursor_next_inline(ctx, cursor)) != GRN_ID_NIL) {
11506 grn_obj *table = grn_ctx_at(ctx, id);
11507 rc = GRN_SUCCESS;
11508 if (table) {
11509 switch (table->header.type) {
11510 case GRN_TABLE_HASH_KEY :
11511 case GRN_TABLE_PAT_KEY:
11512 case GRN_TABLE_DAT_KEY:
11513 case GRN_TABLE_NO_KEY:
11514 rc = grn_obj_flush_recursive(ctx, table);
11515 break;
11516 }
11517 } else {
11518 if (ctx->rc != GRN_SUCCESS) {
11519 ERRCLR(ctx);
11520 }
11521 }
11522 if (rc != GRN_SUCCESS) {
11523 break;
11524 }
11525 }
11526 grn_table_cursor_close(ctx, cursor);
11527 }
11528 if (rc == GRN_SUCCESS) {
11529 rc = grn_obj_flush(ctx, obj);
11530 }
11531 break;
11532 case GRN_TABLE_NO_KEY :
11533 case GRN_TABLE_HASH_KEY :
11534 case GRN_TABLE_PAT_KEY :
11535 case GRN_TABLE_DAT_KEY :
11536 {
11537 grn_hash *columns;
11538 columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
11539 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
11540 if (!columns) {
11541 GRN_API_RETURN(ctx->rc);
11542 }
11543
11544 if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)columns) > 0) {
11545 grn_id *key;
11546 GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
11547 grn_obj *column = grn_ctx_at(ctx, *key);
11548 if (column) {
11549 rc = grn_obj_flush(ctx, column);
11550 if (rc != GRN_SUCCESS) {
11551 break;
11552 }
11553 }
11554 });
11555 }
11556 grn_hash_close(ctx, columns);
11557 }
11558
11559 if (rc == GRN_SUCCESS) {
11560 rc = grn_obj_flush(ctx, obj);
11561 }
11562 break;
11563 case GRN_COLUMN_FIX_SIZE :
11564 case GRN_COLUMN_VAR_SIZE :
11565 case GRN_COLUMN_INDEX :
11566 rc = grn_obj_flush(ctx, obj);
11567 break;
11568 default :
11569 {
11570 grn_obj inspected;
11571 GRN_TEXT_INIT(&inspected, 0);
11572 grn_inspect(ctx, &inspected, obj);
11573 ERR(GRN_INVALID_ARGUMENT,
11574 "[flush] object must be DB, table or column: <%.*s>",
11575 (int)GRN_TEXT_LEN(&inspected),
11576 GRN_TEXT_VALUE(&inspected));
11577 rc = ctx->rc;
11578 GRN_OBJ_FIN(ctx, &inspected);
11579 }
11580 break;
11581 }
11582
11583 GRN_API_RETURN(rc);
11584}
11585
11586grn_obj *
11587grn_obj_db(grn_ctx *ctx, grn_obj *obj)
11588{
11589 grn_obj *db = NULL;
11590 GRN_API_ENTER;
11591 if (GRN_DB_OBJP(obj)) { db = DB_OBJ(obj)->db; }
11592 GRN_API_RETURN(db);
11593}
11594
11595grn_id
11596grn_obj_id(grn_ctx *ctx, grn_obj *obj)
11597{
11598 grn_id id = GRN_ID_NIL;
11599 GRN_API_ENTER;
11600 if (GRN_DB_OBJP(obj)) {
11601 id = DB_OBJ(obj)->id;
11602 }
11603 GRN_API_RETURN(id);
11604}
11605
11606int
11607grn_obj_defrag(grn_ctx *ctx, grn_obj *obj, int threshold)
11608{
11609 int r = 0;
11610 GRN_API_ENTER;
11611 switch (obj->header.type) {
11612 case GRN_DB:
11613 {
11614 grn_table_cursor *cur;
11615 if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
11616 grn_id id;
11617 while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
11618 grn_obj *ja = grn_ctx_at(ctx, id);
11619 if (ja && ja->header.type == GRN_COLUMN_VAR_SIZE) {
11620 r += grn_ja_defrag(ctx, (grn_ja *)ja, threshold);
11621 }
11622 }
11623 grn_table_cursor_close(ctx, cur);
11624 }
11625 }
11626 break;
11627 case GRN_TABLE_HASH_KEY :
11628 case GRN_TABLE_PAT_KEY :
11629 case GRN_TABLE_DAT_KEY :
11630 case GRN_TABLE_NO_KEY :
11631 {
11632 grn_hash *cols;
11633 if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
11634 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
11635 if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
11636 grn_id *key;
11637 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
11638 grn_obj *col = grn_ctx_at(ctx, *key);
11639 if (col) {
11640 r += grn_obj_defrag(ctx, col, threshold);
11641 grn_obj_unlink(ctx, col);
11642 }
11643 });
11644 }
11645 grn_hash_close(ctx, cols);
11646 }
11647 }
11648 break;
11649 case GRN_COLUMN_VAR_SIZE:
11650 r = grn_ja_defrag(ctx, (grn_ja *)obj, threshold);
11651 break;
11652 }
11653 GRN_API_RETURN(r);
11654}
11655
11656/**** sort ****/
11657
11658typedef struct {
11659 grn_id id;
11660 uint32_t size;
11661 const void *value;
11662} sort_reference_entry;
11663
11664enum {
11665 KEY_ID = 0,
11666 KEY_BULK,
11667 KEY_INT8,
11668 KEY_INT16,
11669 KEY_INT32,
11670 KEY_INT64,
11671 KEY_UINT8,
11672 KEY_UINT16,
11673 KEY_UINT32,
11674 KEY_UINT64,
11675 KEY_FLOAT32,
11676 KEY_FLOAT64,
11677};
11678
11679#define CMPNUM(type) do {\
11680 if (as) {\
11681 if (bs) {\
11682 type va = *((type *)(ap));\
11683 type vb = *((type *)(bp));\
11684 if (va != vb) { return va > vb; }\
11685 } else {\
11686 return 1;\
11687 }\
11688 } else {\
11689 if (bs) { return 0; }\
11690 }\
11691} while (0)
11692
11693inline static int
11694compare_reference(grn_ctx *ctx,
11695 sort_reference_entry *a, sort_reference_entry *b,
11696 grn_table_sort_key *keys, int n_keys)
11697{
11698 int i;
11699 uint8_t type;
11700 uint32_t as, bs;
11701 const unsigned char *ap, *bp;
11702 for (i = 0; i < n_keys; i++, keys++) {
11703 if (i) {
11704 const char *ap_raw, *bp_raw;
11705 if (keys->flags & GRN_TABLE_SORT_DESC) {
11706 ap_raw = grn_obj_get_value_(ctx, keys->key, b->id, &as);
11707 bp_raw = grn_obj_get_value_(ctx, keys->key, a->id, &bs);
11708 } else {
11709 ap_raw = grn_obj_get_value_(ctx, keys->key, a->id, &as);
11710 bp_raw = grn_obj_get_value_(ctx, keys->key, b->id, &bs);
11711 }
11712 ap = (const unsigned char *)ap_raw;
11713 bp = (const unsigned char *)bp_raw;
11714 } else {
11715 if (keys->flags & GRN_TABLE_SORT_DESC) {
11716 ap = b->value; as = b->size;
11717 bp = a->value; bs = a->size;
11718 } else {
11719 ap = a->value; as = a->size;
11720 bp = b->value; bs = b->size;
11721 }
11722 }
11723 type = keys->offset;
11724 switch (type) {
11725 case KEY_ID :
11726 if (ap != bp) { return ap > bp; }
11727 break;
11728 case KEY_BULK :
11729 for (;; ap++, bp++, as--, bs--) {
11730 if (!as) { if (bs) { return 0; } else { break; } }
11731 if (!bs) { return 1; }
11732 if (*ap < *bp) { return 0; }
11733 if (*ap > *bp) { return 1; }
11734 }
11735 break;
11736 case KEY_INT8 :
11737 CMPNUM(int8_t);
11738 break;
11739 case KEY_INT16 :
11740 CMPNUM(int16_t);
11741 break;
11742 case KEY_INT32 :
11743 CMPNUM(int32_t);
11744 break;
11745 case KEY_INT64 :
11746 CMPNUM(int64_t);
11747 break;
11748 case KEY_UINT8 :
11749 CMPNUM(uint8_t);
11750 break;
11751 case KEY_UINT16 :
11752 CMPNUM(uint16_t);
11753 break;
11754 case KEY_UINT32 :
11755 CMPNUM(uint32_t);
11756 break;
11757 case KEY_UINT64 :
11758 CMPNUM(uint64_t);
11759 break;
11760 case KEY_FLOAT32 :
11761 if (as) {
11762 if (bs) {
11763 float va = *((float *)(ap));
11764 float vb = *((float *)(bp));
11765 if (va < vb || va > vb) { return va > vb; }
11766 } else {
11767 return 1;
11768 }
11769 } else {
11770 if (bs) { return 0; }
11771 }
11772 break;
11773 case KEY_FLOAT64 :
11774 if (as) {
11775 if (bs) {
11776 double va = *((double *)(ap));
11777 double vb = *((double *)(bp));
11778 if (va < vb || va > vb) { return va > vb; }
11779 } else {
11780 return 1;
11781 }
11782 } else {
11783 if (bs) { return 0; }
11784 }
11785 break;
11786 }
11787 }
11788 return 0;
11789}
11790
11791inline static void
11792swap_reference(sort_reference_entry *a, sort_reference_entry *b)
11793{
11794 sort_reference_entry c_ = *a;
11795 *a = *b;
11796 *b = c_;
11797}
11798
11799inline static sort_reference_entry *
11800part_reference(grn_ctx *ctx,
11801 sort_reference_entry *b, sort_reference_entry *e,
11802 grn_table_sort_key *keys, int n_keys)
11803{
11804 sort_reference_entry *c;
11805 intptr_t d = e - b;
11806 if (compare_reference(ctx, b, e, keys, n_keys)) {
11807 swap_reference(b, e);
11808 }
11809 if (d < 2) { return NULL; }
11810 c = b + (d >> 1);
11811 if (compare_reference(ctx, b, c, keys, n_keys)) {
11812 swap_reference(b, c);
11813 } else {
11814 if (compare_reference(ctx, c, e, keys, n_keys)) {
11815 swap_reference(c, e);
11816 }
11817 }
11818 if (d < 3) { return NULL; }
11819 b++;
11820 swap_reference(b, c);
11821 c = b;
11822 for (;;) {
11823 do {
11824 b++;
11825 } while (compare_reference(ctx, c, b, keys, n_keys));
11826 do {
11827 e--;
11828 } while (compare_reference(ctx, e, c, keys, n_keys));
11829 if (b >= e) { break; }
11830 swap_reference(b, e);
11831 }
11832 swap_reference(c, e);
11833 return e;
11834}
11835
11836static void
11837sort_reference(grn_ctx *ctx,
11838 sort_reference_entry *head, sort_reference_entry *tail,
11839 int from, int to,
11840 grn_table_sort_key *keys, int n_keys)
11841{
11842 sort_reference_entry *c;
11843 if (head < tail && (c = part_reference(ctx, head, tail, keys, n_keys))) {
11844 intptr_t m = c - head + 1;
11845 if (from < m - 1) {
11846 sort_reference(ctx, head, c - 1, from, to, keys, n_keys);
11847 }
11848 if (m < to) {
11849 sort_reference(ctx, c + 1, tail, from - m, to - m, keys, n_keys);
11850 }
11851 }
11852}
11853
11854static sort_reference_entry *
11855pack_reference(grn_ctx *ctx, grn_obj *table,
11856 sort_reference_entry *head, sort_reference_entry *tail,
11857 grn_table_sort_key *keys, int n_keys)
11858{
11859 int i = 0;
11860 sort_reference_entry e, c;
11861 grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
11862 if (!tc) { return NULL; }
11863 if ((c.id = grn_table_cursor_next_inline(ctx, tc))) {
11864 c.value = grn_obj_get_value_(ctx, keys->key, c.id, &c.size);
11865 while ((e.id = grn_table_cursor_next_inline(ctx, tc))) {
11866 e.value = grn_obj_get_value_(ctx, keys->key, e.id, &e.size);
11867 if (compare_reference(ctx, &c, &e, keys, n_keys)) {
11868 *head++ = e;
11869 } else {
11870 *tail-- = e;
11871 }
11872 i++;
11873 }
11874 *head = c;
11875 i++;
11876 }
11877 grn_table_cursor_close(ctx, tc);
11878 return i > 2 ? head : NULL;
11879}
11880
11881static int
11882grn_table_sort_reference(grn_ctx *ctx, grn_obj *table,
11883 int offset, int limit,
11884 grn_obj *result,
11885 grn_table_sort_key *keys, int n_keys)
11886{
11887 int e, n;
11888 sort_reference_entry *array, *ep;
11889 e = offset + limit;
11890 n = grn_table_size(ctx, table);
11891 if (!(array = GRN_MALLOC(sizeof(sort_reference_entry) * n))) {
11892 return 0;
11893 }
11894 if ((ep = pack_reference(ctx, table, array, array + n - 1, keys, n_keys))) {
11895 intptr_t m = ep - array + 1;
11896 if (offset < m - 1) {
11897 sort_reference(ctx, array, ep - 1, offset, e, keys, n_keys);
11898 }
11899 if (m < e) {
11900 sort_reference(ctx, ep + 1, array + n - 1, offset - m, e - m, keys, n_keys);
11901 }
11902 }
11903 {
11904 int i;
11905 grn_id *v;
11906 for (i = 0, ep = array + offset; i < limit && ep < array + n; i++, ep++) {
11907 if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
11908 *v = ep->id;
11909 }
11910 GRN_FREE(array);
11911 return i;
11912 }
11913}
11914
11915
11916typedef struct {
11917 grn_id id;
11918 grn_obj value;
11919} sort_value_entry;
11920
11921inline static int
11922compare_value(grn_ctx *ctx,
11923 sort_value_entry *a, sort_value_entry *b,
11924 grn_table_sort_key *keys, int n_keys,
11925 grn_obj *a_buffer, grn_obj *b_buffer)
11926{
11927 int i;
11928 uint8_t type;
11929 uint32_t as, bs;
11930 const unsigned char *ap, *bp;
11931 for (i = 0; i < n_keys; i++, keys++) {
11932 if (i) {
11933 GRN_BULK_REWIND(a_buffer);
11934 GRN_BULK_REWIND(b_buffer);
11935 if (keys->flags & GRN_TABLE_SORT_DESC) {
11936 grn_obj_get_value(ctx, keys->key, b->id, a_buffer);
11937 grn_obj_get_value(ctx, keys->key, a->id, b_buffer);
11938 } else {
11939 grn_obj_get_value(ctx, keys->key, a->id, a_buffer);
11940 grn_obj_get_value(ctx, keys->key, b->id, b_buffer);
11941 }
11942 ap = (const unsigned char *)GRN_BULK_HEAD(a_buffer);
11943 as = GRN_BULK_VSIZE(a_buffer);
11944 bp = (const unsigned char *)GRN_BULK_HEAD(b_buffer);
11945 bs = GRN_BULK_VSIZE(b_buffer);
11946 } else {
11947 if (keys->flags & GRN_TABLE_SORT_DESC) {
11948 ap = (const unsigned char *)GRN_BULK_HEAD(&b->value);
11949 as = GRN_BULK_VSIZE(&b->value);
11950 bp = (const unsigned char *)GRN_BULK_HEAD(&a->value);
11951 bs = GRN_BULK_VSIZE(&a->value);
11952 } else {
11953 ap = (const unsigned char *)GRN_BULK_HEAD(&a->value);
11954 as = GRN_BULK_VSIZE(&a->value);
11955 bp = (const unsigned char *)GRN_BULK_HEAD(&b->value);
11956 bs = GRN_BULK_VSIZE(&b->value);
11957 }
11958 }
11959 type = keys->offset;
11960 switch (type) {
11961 case KEY_ID :
11962 if (ap != bp) { return ap > bp; }
11963 break;
11964 case KEY_BULK :
11965 for (;; ap++, bp++, as--, bs--) {
11966 if (!as) { if (bs) { return 0; } else { break; } }
11967 if (!bs) { return 1; }
11968 if (*ap < *bp) { return 0; }
11969 if (*ap > *bp) { return 1; }
11970 }
11971 break;
11972 case KEY_INT8 :
11973 CMPNUM(int8_t);
11974 break;
11975 case KEY_INT16 :
11976 CMPNUM(int16_t);
11977 break;
11978 case KEY_INT32 :
11979 CMPNUM(int32_t);
11980 break;
11981 case KEY_INT64 :
11982 CMPNUM(int64_t);
11983 break;
11984 case KEY_UINT8 :
11985 CMPNUM(uint8_t);
11986 break;
11987 case KEY_UINT16 :
11988 CMPNUM(uint16_t);
11989 break;
11990 case KEY_UINT32 :
11991 CMPNUM(uint32_t);
11992 break;
11993 case KEY_UINT64 :
11994 CMPNUM(uint64_t);
11995 break;
11996 case KEY_FLOAT32 :
11997 if (as) {
11998 if (bs) {
11999 float va = *((float *)(ap));
12000 float vb = *((float *)(bp));
12001 if (va < vb || va > vb) { return va > vb; }
12002 } else {
12003 return 1;
12004 }
12005 } else {
12006 if (bs) { return 0; }
12007 }
12008 break;
12009 case KEY_FLOAT64 :
12010 if (as) {
12011 if (bs) {
12012 double va = *((double *)(ap));
12013 double vb = *((double *)(bp));
12014 if (va < vb || va > vb) { return va > vb; }
12015 } else {
12016 return 1;
12017 }
12018 } else {
12019 if (bs) { return 0; }
12020 }
12021 break;
12022 }
12023 }
12024 return 0;
12025}
12026
12027inline static void
12028swap_value(sort_value_entry *a, sort_value_entry *b)
12029{
12030 sort_value_entry c_ = *a;
12031 *a = *b;
12032 *b = c_;
12033}
12034
12035inline static sort_value_entry *
12036part_value(grn_ctx *ctx,
12037 sort_value_entry *b, sort_value_entry *e,
12038 grn_table_sort_key *keys, int n_keys,
12039 grn_obj *a_buffer, grn_obj *b_buffer)
12040{
12041 sort_value_entry *c;
12042 intptr_t d = e - b;
12043 if (compare_value(ctx, b, e, keys, n_keys, a_buffer, b_buffer)) {
12044 swap_value(b, e);
12045 }
12046 if (d < 2) { return NULL; }
12047 c = b + (d >> 1);
12048 if (compare_value(ctx, b, c, keys, n_keys, a_buffer, b_buffer)) {
12049 swap_value(b, c);
12050 } else {
12051 if (compare_value(ctx, c, e, keys, n_keys, a_buffer, b_buffer)) {
12052 swap_value(c, e);
12053 }
12054 }
12055 if (d < 3) { return NULL; }
12056 b++;
12057 swap_value(b, c);
12058 c = b;
12059 for (;;) {
12060 do {
12061 b++;
12062 } while (compare_value(ctx, c, b, keys, n_keys, a_buffer, b_buffer));
12063 do {
12064 e--;
12065 } while (compare_value(ctx, e, c, keys, n_keys, a_buffer, b_buffer));
12066 if (b >= e) { break; }
12067 swap_value(b, e);
12068 }
12069 swap_value(c, e);
12070 return e;
12071}
12072
12073static void
12074sort_value(grn_ctx *ctx,
12075 sort_value_entry *head, sort_value_entry *tail,
12076 int from, int to,
12077 grn_table_sort_key *keys, int n_keys,
12078 grn_obj *a_buffer, grn_obj *b_buffer)
12079{
12080 sort_value_entry *c;
12081 if (head < tail && (c = part_value(ctx, head, tail, keys, n_keys,
12082 a_buffer, b_buffer))) {
12083 intptr_t m = c - head + 1;
12084 if (from < m - 1) {
12085 sort_value(ctx, head, c - 1, from, to, keys, n_keys, a_buffer, b_buffer);
12086 }
12087 if (m < to) {
12088 sort_value(ctx, c + 1, tail, from - m, to - m, keys, n_keys,
12089 a_buffer, b_buffer);
12090 }
12091 }
12092}
12093
12094static sort_value_entry *
12095pack_value(grn_ctx *ctx, grn_obj *table,
12096 sort_value_entry *head, sort_value_entry *tail,
12097 grn_table_sort_key *keys, int n_keys,
12098 grn_obj *a_buffer, grn_obj *b_buffer)
12099{
12100 int i = 0;
12101 sort_value_entry e, c;
12102 grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
12103 if (!tc) { return NULL; }
12104 if ((c.id = grn_table_cursor_next_inline(ctx, tc))) {
12105 GRN_TEXT_INIT(&c.value, 0);
12106 grn_obj_get_value(ctx, keys->key, c.id, &c.value);
12107 while ((e.id = grn_table_cursor_next_inline(ctx, tc))) {
12108 GRN_TEXT_INIT(&e.value, 0);
12109 grn_obj_get_value(ctx, keys->key, e.id, &e.value);
12110 if (compare_value(ctx, &c, &e, keys, n_keys, a_buffer, b_buffer)) {
12111 *head++ = e;
12112 } else {
12113 *tail-- = e;
12114 }
12115 i++;
12116 }
12117 *head = c;
12118 i++;
12119 }
12120 grn_table_cursor_close(ctx, tc);
12121 return i > 2 ? head : NULL;
12122}
12123
12124static int
12125grn_table_sort_value(grn_ctx *ctx, grn_obj *table,
12126 int offset, int limit,
12127 grn_obj *result,
12128 grn_table_sort_key *keys, int n_keys)
12129{
12130 int e, n;
12131 sort_value_entry *array, *ep;
12132 e = offset + limit;
12133 n = grn_table_size(ctx, table);
12134 if (!(array = GRN_MALLOC(sizeof(sort_value_entry) * n))) {
12135 return 0;
12136 }
12137 {
12138 grn_obj a_buffer;
12139 grn_obj b_buffer;
12140 GRN_TEXT_INIT(&a_buffer, 0);
12141 GRN_TEXT_INIT(&b_buffer, 0);
12142 if ((ep = pack_value(ctx, table, array, array + n - 1, keys, n_keys,
12143 &a_buffer, &b_buffer))) {
12144 intptr_t m = ep - array + 1;
12145 if (offset < m - 1) {
12146 sort_value(ctx, array, ep - 1, offset, e, keys, n_keys,
12147 &a_buffer, &b_buffer);
12148 }
12149 if (m < e) {
12150 sort_value(ctx, ep + 1, array + n - 1, offset - m, e - m, keys, n_keys,
12151 &a_buffer, &b_buffer);
12152 }
12153 }
12154 GRN_OBJ_FIN(ctx, &a_buffer);
12155 GRN_OBJ_FIN(ctx, &b_buffer);
12156 }
12157 {
12158 int i;
12159 grn_id *v;
12160 for (i = 0, ep = array + offset; i < limit && ep < array + n; i++, ep++) {
12161 if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
12162 *v = ep->id;
12163 }
12164 GRN_FREE(array);
12165 return i;
12166 }
12167}
12168
12169static grn_bool
12170is_compressed_column(grn_ctx *ctx, grn_obj *obj)
12171{
12172 grn_obj *target_obj;
12173
12174 if (!obj) {
12175 return GRN_FALSE;
12176 }
12177
12178 if (obj->header.type == GRN_ACCESSOR) {
12179 grn_accessor *a = (grn_accessor *)obj;
12180 while (a->next) {
12181 a = a->next;
12182 }
12183 target_obj = a->obj;
12184 } else {
12185 target_obj = obj;
12186 }
12187
12188 if (target_obj->header.type != GRN_COLUMN_VAR_SIZE) {
12189 return GRN_FALSE;
12190 }
12191
12192 switch (target_obj->header.flags & GRN_OBJ_COMPRESS_MASK) {
12193 case GRN_OBJ_COMPRESS_ZLIB :
12194 case GRN_OBJ_COMPRESS_LZ4 :
12195 case GRN_OBJ_COMPRESS_ZSTD :
12196 return GRN_TRUE;
12197 default :
12198 return GRN_FALSE;
12199 }
12200}
12201
12202static grn_bool
12203is_sub_record_accessor(grn_ctx *ctx, grn_obj *obj)
12204{
12205 grn_accessor *accessor;
12206
12207 if (!obj) {
12208 return GRN_FALSE;
12209 }
12210
12211 if (obj->header.type != GRN_ACCESSOR) {
12212 return GRN_FALSE;
12213 }
12214
12215 for (accessor = (grn_accessor *)obj; accessor; accessor = accessor->next) {
12216 switch (accessor->action) {
12217 case GRN_ACCESSOR_GET_VALUE :
12218 if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(accessor->obj)) {
12219 return GRN_TRUE;
12220 }
12221 break;
12222 default :
12223 break;
12224 }
12225 }
12226
12227 return GRN_FALSE;
12228}
12229
12230static grn_bool
12231is_encoded_pat_key_accessor(grn_ctx *ctx, grn_obj *obj)
12232{
12233 grn_accessor *accessor;
12234
12235 if (!grn_obj_is_accessor(ctx, obj)) {
12236 return GRN_FALSE;
12237 }
12238
12239 accessor = (grn_accessor *)obj;
12240 while (accessor->next) {
12241 accessor = accessor->next;
12242 }
12243
12244 if (accessor->action != GRN_ACCESSOR_GET_KEY) {
12245 return GRN_FALSE;
12246 }
12247
12248 if (accessor->obj->header.type != GRN_TABLE_PAT_KEY) {
12249 return GRN_FALSE;
12250 }
12251
12252 return grn_pat_is_key_encoded(ctx, (grn_pat *)(accessor->obj));
12253}
12254
12255static int
12256range_is_idp(grn_obj *obj)
12257{
12258 if (obj && obj->header.type == GRN_ACCESSOR) {
12259 grn_accessor *a;
12260 for (a = (grn_accessor *)obj; a; a = a->next) {
12261 if (a->action == GRN_ACCESSOR_GET_ID) { return 1; }
12262 }
12263 }
12264 return 0;
12265}
12266
12267int
12268grn_table_sort(grn_ctx *ctx, grn_obj *table, int offset, int limit,
12269 grn_obj *result, grn_table_sort_key *keys, int n_keys)
12270{
12271 grn_rc rc;
12272 grn_obj *index;
12273 int n, e, i = 0;
12274 GRN_API_ENTER;
12275 if (!n_keys || !keys) {
12276 WARN(GRN_INVALID_ARGUMENT, "keys is null");
12277 goto exit;
12278 }
12279 if (!table) {
12280 WARN(GRN_INVALID_ARGUMENT, "table is null");
12281 goto exit;
12282 }
12283 if (!(result && result->header.type == GRN_TABLE_NO_KEY)) {
12284 WARN(GRN_INVALID_ARGUMENT, "result is not a array");
12285 goto exit;
12286 }
12287 n = grn_table_size(ctx, table);
12288 if ((rc = grn_normalize_offset_and_limit(ctx, n, &offset, &limit))) {
12289 ERR(rc, "grn_normalize_offset_and_limit failed");
12290 goto exit;
12291 } else {
12292 e = offset + limit;
12293 }
12294 if (keys->flags & GRN_TABLE_SORT_GEO) {
12295 if (n_keys == 2) {
12296 i = grn_geo_table_sort(ctx, table, offset, limit, result,
12297 keys[0].key, keys[1].key);
12298 } else {
12299 i = 0;
12300 }
12301 goto exit;
12302 }
12303 if (n_keys == 1 && !GRN_ACCESSORP(keys->key) &&
12304 grn_column_index(ctx, keys->key, GRN_OP_LESS, &index, 1, NULL)) {
12305 grn_id tid;
12306 grn_pat *lexicon = (grn_pat *)grn_ctx_at(ctx, index->header.domain);
12307 grn_pat_cursor *pc = grn_pat_cursor_open(ctx, lexicon, NULL, 0, NULL, 0,
12308 0 /* offset : can be used in unique index */,
12309 -1 /* limit : can be used in unique index */,
12310 (keys->flags & GRN_TABLE_SORT_DESC)
12311 ? GRN_CURSOR_DESCENDING
12312 : GRN_CURSOR_ASCENDING);
12313 if (pc) {
12314 while (i < e && (tid = grn_pat_cursor_next(ctx, pc))) {
12315 grn_ii_cursor *ic = grn_ii_cursor_open(ctx, (grn_ii *)index, tid, 0, 0, 1, 0);
12316 if (ic) {
12317 grn_posting *posting;
12318 while (i < e && (posting = grn_ii_cursor_next(ctx, ic))) {
12319 if (offset <= i) {
12320 grn_id *v;
12321 if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
12322 *v = posting->rid;
12323 }
12324 i++;
12325 }
12326 grn_ii_cursor_close(ctx, ic);
12327 }
12328 }
12329 grn_pat_cursor_close(ctx, pc);
12330 }
12331 } else {
12332 int j;
12333 grn_bool have_compressed_column = GRN_FALSE;
12334 grn_bool have_sub_record_accessor = GRN_FALSE;
12335 grn_bool have_encoded_pat_key_accessor = GRN_FALSE;
12336 grn_bool have_index_value_get = GRN_FALSE;
12337 grn_table_sort_key *kp;
12338 for (kp = keys, j = n_keys; j; kp++, j--) {
12339 if (is_compressed_column(ctx, kp->key)) {
12340 have_compressed_column = GRN_TRUE;
12341 }
12342 if (is_sub_record_accessor(ctx, kp->key)) {
12343 have_sub_record_accessor = GRN_TRUE;
12344 }
12345 if (is_encoded_pat_key_accessor(ctx, kp->key)) {
12346 have_encoded_pat_key_accessor = GRN_TRUE;
12347 }
12348 if (range_is_idp(kp->key)) {
12349 kp->offset = KEY_ID;
12350 } else {
12351 grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, kp->key));
12352 if (range->header.type == GRN_TYPE) {
12353 if (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
12354 kp->offset = KEY_BULK;
12355 } else {
12356 uint8_t key_type = range->header.flags & GRN_OBJ_KEY_MASK;
12357 switch (key_type) {
12358 case GRN_OBJ_KEY_UINT :
12359 case GRN_OBJ_KEY_GEO_POINT :
12360 switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
12361 case 1 :
12362 kp->offset = KEY_UINT8;
12363 break;
12364 case 2 :
12365 kp->offset = KEY_UINT16;
12366 break;
12367 case 4 :
12368 kp->offset = KEY_UINT32;
12369 break;
12370 case 8 :
12371 kp->offset = KEY_UINT64;
12372 break;
12373 default :
12374 ERR(GRN_INVALID_ARGUMENT, "unsupported uint value");
12375 goto exit;
12376 }
12377 break;
12378 case GRN_OBJ_KEY_INT :
12379 switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
12380 case 1 :
12381 kp->offset = KEY_INT8;
12382 break;
12383 case 2 :
12384 kp->offset = KEY_INT16;
12385 break;
12386 case 4 :
12387 kp->offset = KEY_INT32;
12388 break;
12389 case 8 :
12390 kp->offset = KEY_INT64;
12391 break;
12392 default :
12393 ERR(GRN_INVALID_ARGUMENT, "unsupported int value");
12394 goto exit;
12395 }
12396 break;
12397 case GRN_OBJ_KEY_FLOAT :
12398 switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
12399 case 4 :
12400 kp->offset = KEY_FLOAT32;
12401 break;
12402 case 8 :
12403 kp->offset = KEY_FLOAT64;
12404 break;
12405 default :
12406 ERR(GRN_INVALID_ARGUMENT, "unsupported float value");
12407 goto exit;
12408 }
12409 break;
12410 }
12411 }
12412 } else {
12413 if (kp->key->header.type == GRN_COLUMN_INDEX) {
12414 have_index_value_get = GRN_TRUE;
12415 }
12416 kp->offset = KEY_UINT32;
12417 }
12418 }
12419 }
12420 if (have_compressed_column ||
12421 have_sub_record_accessor ||
12422 have_encoded_pat_key_accessor ||
12423 have_index_value_get) {
12424 i = grn_table_sort_value(ctx, table, offset, limit, result,
12425 keys, n_keys);
12426 } else {
12427 i = grn_table_sort_reference(ctx, table, offset, limit, result,
12428 keys, n_keys);
12429 }
12430 }
12431exit :
12432 GRN_API_RETURN(i);
12433}
12434
12435static grn_obj *
12436deftype(grn_ctx *ctx, const char *name,
12437 grn_obj_flags flags, unsigned int size)
12438{
12439 grn_obj *o = grn_ctx_get(ctx, name, strlen(name));
12440 if (!o) { o = grn_type_create(ctx, name, strlen(name), flags, size); }
12441 return o;
12442}
12443
12444grn_rc
12445grn_db_init_builtin_types(grn_ctx *ctx)
12446{
12447 grn_id id;
12448 grn_obj *obj, *db = ctx->impl->db;
12449 char buf[] = "Sys00";
12450 grn_obj_register(ctx, db, buf, 5);
12451 obj = deftype(ctx, "Object",
12452 GRN_OBJ_KEY_UINT, sizeof(uint64_t));
12453 if (!obj || DB_OBJ(obj)->id != GRN_DB_OBJECT) { return GRN_FILE_CORRUPT; }
12454 obj = deftype(ctx, "Bool",
12455 GRN_OBJ_KEY_UINT, sizeof(uint8_t));
12456 if (!obj || DB_OBJ(obj)->id != GRN_DB_BOOL) { return GRN_FILE_CORRUPT; }
12457 obj = deftype(ctx, "Int8",
12458 GRN_OBJ_KEY_INT, sizeof(int8_t));
12459 if (!obj || DB_OBJ(obj)->id != GRN_DB_INT8) { return GRN_FILE_CORRUPT; }
12460 obj = deftype(ctx, "UInt8",
12461 GRN_OBJ_KEY_UINT, sizeof(uint8_t));
12462 if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT8) { return GRN_FILE_CORRUPT; }
12463 obj = deftype(ctx, "Int16",
12464 GRN_OBJ_KEY_INT, sizeof(int16_t));
12465 if (!obj || DB_OBJ(obj)->id != GRN_DB_INT16) { return GRN_FILE_CORRUPT; }
12466 obj = deftype(ctx, "UInt16",
12467 GRN_OBJ_KEY_UINT, sizeof(uint16_t));
12468 if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT16) { return GRN_FILE_CORRUPT; }
12469 obj = deftype(ctx, "Int32",
12470 GRN_OBJ_KEY_INT, sizeof(int32_t));
12471 if (!obj || DB_OBJ(obj)->id != GRN_DB_INT32) { return GRN_FILE_CORRUPT; }
12472 obj = deftype(ctx, "UInt32",
12473 GRN_OBJ_KEY_UINT, sizeof(uint32_t));
12474 if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT32) { return GRN_FILE_CORRUPT; }
12475 obj = deftype(ctx, "Int64",
12476 GRN_OBJ_KEY_INT, sizeof(int64_t));
12477 if (!obj || DB_OBJ(obj)->id != GRN_DB_INT64) { return GRN_FILE_CORRUPT; }
12478 obj = deftype(ctx, "UInt64",
12479 GRN_OBJ_KEY_UINT, sizeof(uint64_t));
12480 if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT64) { return GRN_FILE_CORRUPT; }
12481 obj = deftype(ctx, "Float",
12482 GRN_OBJ_KEY_FLOAT, sizeof(double));
12483 if (!obj || DB_OBJ(obj)->id != GRN_DB_FLOAT) { return GRN_FILE_CORRUPT; }
12484 obj = deftype(ctx, "Time",
12485 GRN_OBJ_KEY_INT, sizeof(int64_t));
12486 if (!obj || DB_OBJ(obj)->id != GRN_DB_TIME) { return GRN_FILE_CORRUPT; }
12487 obj = deftype(ctx, "ShortText",
12488 GRN_OBJ_KEY_VAR_SIZE, GRN_TABLE_MAX_KEY_SIZE);
12489 if (!obj || DB_OBJ(obj)->id != GRN_DB_SHORT_TEXT) { return GRN_FILE_CORRUPT; }
12490 obj = deftype(ctx, "Text",
12491 GRN_OBJ_KEY_VAR_SIZE, 1 << 16);
12492 if (!obj || DB_OBJ(obj)->id != GRN_DB_TEXT) { return GRN_FILE_CORRUPT; }
12493 obj = deftype(ctx, "LongText",
12494 GRN_OBJ_KEY_VAR_SIZE, 1 << 31);
12495 if (!obj || DB_OBJ(obj)->id != GRN_DB_LONG_TEXT) { return GRN_FILE_CORRUPT; }
12496 obj = deftype(ctx, "TokyoGeoPoint",
12497 GRN_OBJ_KEY_GEO_POINT, sizeof(grn_geo_point));
12498 if (!obj || DB_OBJ(obj)->id != GRN_DB_TOKYO_GEO_POINT) { return GRN_FILE_CORRUPT; }
12499 obj = deftype(ctx, "WGS84GeoPoint",
12500 GRN_OBJ_KEY_GEO_POINT, sizeof(grn_geo_point));
12501 if (!obj || DB_OBJ(obj)->id != GRN_DB_WGS84_GEO_POINT) { return GRN_FILE_CORRUPT; }
12502 for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_DB_MECAB; id++) {
12503 grn_itoh(id, buf + 3, 2);
12504 grn_obj_register(ctx, db, buf, 5);
12505 }
12506#ifdef GRN_WITH_MECAB
12507 if (grn_db_init_mecab_tokenizer(ctx)) {
12508 ERRCLR(ctx);
12509#endif
12510 grn_obj_register(ctx, db, "TokenMecab", 10);
12511#ifdef GRN_WITH_MECAB
12512 }
12513#endif
12514 grn_db_init_builtin_tokenizers(ctx);
12515 grn_db_init_builtin_normalizers(ctx);
12516 grn_db_init_builtin_scorers(ctx);
12517 for (id = grn_db_curr_id(ctx, db) + 1; id < 128; id++) {
12518 grn_itoh(id, buf + 3, 2);
12519 grn_obj_register(ctx, db, buf, 5);
12520 }
12521 grn_db_init_builtin_commands(ctx);
12522 grn_db_init_builtin_window_functions(ctx);
12523 for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_N_RESERVED_TYPES; id++) {
12524 grn_itoh(id, buf + 3, 2);
12525 grn_obj_register(ctx, db, buf, 5);
12526 }
12527 return ctx->rc;
12528}
12529
12530#define MULTI_COLUMN_INDEXP(i) (DB_OBJ(i)->source_size > sizeof(grn_id))
12531
12532static grn_obj *
12533grn_index_column_get_tokenizer(grn_ctx *ctx, grn_obj *index_column)
12534{
12535 grn_obj *tokenizer;
12536 grn_obj *lexicon;
12537
12538 lexicon = grn_ctx_at(ctx, index_column->header.domain);
12539 if (!lexicon) {
12540 return NULL;
12541 }
12542
12543 grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
12544 return tokenizer;
12545}
12546
12547static grn_bool
12548is_full_text_searchable_index(grn_ctx *ctx, grn_obj *index_column)
12549{
12550 grn_obj *tokenizer;
12551
12552 tokenizer = grn_index_column_get_tokenizer(ctx, index_column);
12553 return tokenizer != NULL;
12554}
12555
12556static int
12557grn_column_find_index_data_column_equal(grn_ctx *ctx, grn_obj *obj,
12558 grn_operator op,
12559 grn_index_datum *index_data,
12560 unsigned int n_index_data,
12561 grn_obj **index_buf, int buf_size,
12562 int *section_buf)
12563{
12564 int n = 0;
12565 grn_obj **ip = index_buf;
12566 grn_hook *hooks;
12567
12568 for (hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
12569 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12570 grn_obj *target = grn_ctx_at(ctx, data->target);
12571 int section;
12572 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12573 if (obj->header.type != GRN_COLUMN_FIX_SIZE) {
12574 if (is_full_text_searchable_index(ctx, target)) { continue; }
12575 }
12576 section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12577 if (section_buf) { *section_buf = section; }
12578 if (n < buf_size) {
12579 *ip++ = target;
12580 }
12581 if (n < n_index_data) {
12582 index_data[n].index = target;
12583 index_data[n].section = section;
12584 }
12585 n++;
12586 }
12587
12588 return n;
12589}
12590
12591static grn_bool
12592is_valid_regexp_index(grn_ctx *ctx, grn_obj *index_column)
12593{
12594 grn_obj *tokenizer;
12595
12596 tokenizer = grn_index_column_get_tokenizer(ctx, index_column);
12597 /* TODO: Restrict to TokenRegexp? */
12598 return tokenizer != NULL;
12599}
12600
12601static int
12602grn_column_find_index_data_column_match(grn_ctx *ctx, grn_obj *obj,
12603 grn_operator op,
12604 grn_index_datum *index_data,
12605 unsigned int n_index_data,
12606 grn_obj **index_buf, int buf_size,
12607 int *section_buf)
12608{
12609 int n = 0;
12610 grn_obj **ip = index_buf;
12611 grn_hook_entry hook_entry;
12612 grn_hook *hooks;
12613 grn_bool prefer_full_text_search_index = GRN_FALSE;
12614
12615 switch (obj->header.type) {
12616 case GRN_TABLE_HASH_KEY :
12617 case GRN_TABLE_PAT_KEY :
12618 case GRN_TABLE_DAT_KEY :
12619 case GRN_TABLE_NO_KEY :
12620 hook_entry = GRN_HOOK_INSERT;
12621 break;
12622 default :
12623 hook_entry = GRN_HOOK_SET;
12624 break;
12625 }
12626
12627 if (op != GRN_OP_REGEXP && !grn_column_is_vector(ctx, obj)) {
12628 prefer_full_text_search_index = GRN_TRUE;
12629 }
12630
12631 if (prefer_full_text_search_index) {
12632 for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
12633 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12634 grn_obj *target = grn_ctx_at(ctx, data->target);
12635 int section;
12636 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12637 if (!is_full_text_searchable_index(ctx, target)) { continue; }
12638 section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12639 if (section_buf) { *section_buf = section; }
12640 if (n < buf_size) {
12641 *ip++ = target;
12642 }
12643 if (n < n_index_data) {
12644 index_data[n].index = target;
12645 index_data[n].section = section;
12646 }
12647 n++;
12648 }
12649 }
12650
12651 for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
12652 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12653 grn_obj *target = grn_ctx_at(ctx, data->target);
12654 int section;
12655
12656 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12657 if (op == GRN_OP_REGEXP && !is_valid_regexp_index(ctx, target)) {
12658 continue;
12659 }
12660
12661 if (prefer_full_text_search_index) {
12662 if (is_full_text_searchable_index(ctx, target)) { continue; }
12663 }
12664
12665 section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12666 if (section_buf) { *section_buf = section; }
12667 if (n < buf_size) {
12668 *ip++ = target;
12669 }
12670 if (n < n_index_data) {
12671 index_data[n].index = target;
12672 index_data[n].section = section;
12673 }
12674 n++;
12675 }
12676
12677 return n;
12678}
12679
12680static int
12681grn_column_find_index_data_column_range(grn_ctx *ctx, grn_obj *obj,
12682 grn_operator op,
12683 grn_index_datum *index_data,
12684 unsigned int n_index_data,
12685 grn_obj **index_buf, int buf_size,
12686 int *section_buf)
12687{
12688 int n = 0;
12689 grn_obj **ip = index_buf;
12690 grn_hook_entry hook_entry;
12691 grn_hook *hooks;
12692
12693 switch (obj->header.type) {
12694 case GRN_TABLE_HASH_KEY :
12695 case GRN_TABLE_PAT_KEY :
12696 case GRN_TABLE_DAT_KEY :
12697 case GRN_TABLE_NO_KEY :
12698 hook_entry = GRN_HOOK_INSERT;
12699 break;
12700 default :
12701 hook_entry = GRN_HOOK_SET;
12702 break;
12703 }
12704
12705 for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
12706 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12707 grn_obj *target = grn_ctx_at(ctx, data->target);
12708 int section;
12709 if (!target) { continue; }
12710 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12711 section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12712 if (section_buf) { *section_buf = section; }
12713 {
12714 grn_obj *tokenizer, *lexicon = grn_ctx_at(ctx, target->header.domain);
12715 if (!lexicon) { continue; }
12716 if (lexicon->header.type != GRN_TABLE_PAT_KEY) { continue; }
12717 /* FIXME: GRN_TABLE_DAT_KEY should be supported */
12718 grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
12719 if (tokenizer) { continue; }
12720 }
12721 if (n < buf_size) {
12722 *ip++ = target;
12723 }
12724 if (n < n_index_data) {
12725 index_data[n].index = target;
12726 index_data[n].section = section;
12727 }
12728 n++;
12729 }
12730
12731 return n;
12732}
12733
12734static grn_bool
12735is_valid_match_index(grn_ctx *ctx, grn_obj *index_column)
12736{
12737 return GRN_TRUE;
12738}
12739
12740static grn_bool
12741is_valid_range_index(grn_ctx *ctx, grn_obj *index_column)
12742{
12743 grn_obj *tokenizer;
12744 grn_obj *lexicon;
12745
12746 lexicon = grn_ctx_at(ctx, index_column->header.domain);
12747 if (!lexicon) { return GRN_FALSE; }
12748 /* FIXME: GRN_TABLE_DAT_KEY should be supported */
12749 if (lexicon->header.type != GRN_TABLE_PAT_KEY) {
12750 grn_obj_unlink(ctx, lexicon);
12751 return GRN_FALSE;
12752 }
12753
12754 grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
12755 grn_obj_unlink(ctx, lexicon);
12756 if (tokenizer) { return GRN_FALSE; }
12757
12758 return GRN_TRUE;
12759}
12760
12761static grn_bool
12762is_valid_index(grn_ctx *ctx, grn_obj *index_column, grn_operator op)
12763{
12764 switch (op) {
12765 case GRN_OP_MATCH :
12766 case GRN_OP_NEAR :
12767 case GRN_OP_NEAR2 :
12768 case GRN_OP_SIMILAR :
12769 return is_valid_match_index(ctx, index_column);
12770 break;
12771 case GRN_OP_LESS :
12772 case GRN_OP_GREATER :
12773 case GRN_OP_LESS_EQUAL :
12774 case GRN_OP_GREATER_EQUAL :
12775 case GRN_OP_CALL :
12776 return is_valid_range_index(ctx, index_column);
12777 break;
12778 case GRN_OP_REGEXP :
12779 return is_valid_regexp_index(ctx, index_column);
12780 break;
12781 default :
12782 return GRN_FALSE;
12783 break;
12784 }
12785}
12786
12787static int
12788find_section(grn_ctx *ctx, grn_obj *index_column, grn_obj *indexed_column)
12789{
12790 int section = 0;
12791 grn_id indexed_column_id;
12792 grn_id *source_ids;
12793 int i, n_source_ids;
12794
12795 indexed_column_id = DB_OBJ(indexed_column)->id;
12796
12797 source_ids = DB_OBJ(index_column)->source;
12798 n_source_ids = DB_OBJ(index_column)->source_size / sizeof(grn_id);
12799 for (i = 0; i < n_source_ids; i++) {
12800 grn_id source_id = source_ids[i];
12801 if (source_id == indexed_column_id) {
12802 section = i + 1;
12803 break;
12804 }
12805 }
12806
12807 return section;
12808}
12809
12810static int
12811grn_column_find_index_data_accessor_index_column(grn_ctx *ctx, grn_accessor *a,
12812 grn_operator op,
12813 grn_index_datum *index_data,
12814 unsigned int n_index_data,
12815 grn_obj **index_buf,
12816 int buf_size,
12817 int *section_buf)
12818{
12819 grn_obj *index_column = a->obj;
12820 int section = 0;
12821
12822 if (!is_valid_index(ctx, index_column, op)) {
12823 return 0;
12824 }
12825
12826 if (a->next) {
12827 int specified_section;
12828 grn_bool is_invalid_section;
12829 if (a->next->next) {
12830 return 0;
12831 }
12832 specified_section = find_section(ctx, index_column, a->next->obj);
12833 is_invalid_section = (specified_section == 0);
12834 if (is_invalid_section) {
12835 return 0;
12836 }
12837 section = specified_section;
12838 if (section_buf) {
12839 *section_buf = section;
12840 }
12841 }
12842 if (buf_size > 0) {
12843 *index_buf = index_column;
12844 }
12845 if (n_index_data > 0) {
12846 index_data[0].index = index_column;
12847 index_data[0].section = section;
12848 }
12849
12850 return 1;
12851}
12852
12853static grn_bool
12854grn_column_find_index_data_accessor_is_key_search(grn_ctx *ctx,
12855 grn_accessor *accessor,
12856 grn_operator op)
12857{
12858 if (accessor->next) {
12859 return GRN_FALSE;
12860 }
12861
12862 if (accessor->action != GRN_ACCESSOR_GET_KEY) {
12863 return GRN_FALSE;
12864 }
12865
12866 if (!grn_obj_is_table(ctx, accessor->obj)) {
12867 return GRN_FALSE;
12868 }
12869
12870 switch (op) {
12871 case GRN_OP_LESS :
12872 case GRN_OP_GREATER :
12873 case GRN_OP_LESS_EQUAL :
12874 case GRN_OP_GREATER_EQUAL :
12875 switch (accessor->obj->header.type) {
12876 case GRN_TABLE_PAT_KEY :
12877 case GRN_TABLE_DAT_KEY :
12878 return GRN_TRUE;
12879 default :
12880 return GRN_FALSE;
12881 }
12882 case GRN_OP_EQUAL :
12883 switch (accessor->obj->header.type) {
12884 case GRN_TABLE_HASH_KEY :
12885 case GRN_TABLE_PAT_KEY :
12886 case GRN_TABLE_DAT_KEY :
12887 return GRN_TRUE;
12888 default :
12889 return GRN_FALSE;
12890 }
12891 default :
12892 return GRN_FALSE;
12893 }
12894}
12895
12896static int
12897grn_column_find_index_data_accessor_match(grn_ctx *ctx, grn_obj *obj,
12898 grn_operator op,
12899 grn_index_datum *index_data,
12900 unsigned n_index_data,
12901 grn_obj **index_buf, int buf_size,
12902 int *section_buf)
12903{
12904 int n = 0;
12905 grn_obj **ip = index_buf;
12906 grn_accessor *a = (grn_accessor *)obj;
12907
12908 while (a) {
12909 grn_hook *hooks;
12910 grn_bool found = GRN_FALSE;
12911 grn_hook_entry entry = (grn_hook_entry)-1;
12912
12913 if (a->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
12914 GRN_OBJ_INDEX_COLUMNP(a->obj)) {
12915 return grn_column_find_index_data_accessor_index_column(ctx, a, op,
12916 index_data,
12917 n_index_data,
12918 index_buf,
12919 buf_size,
12920 section_buf);
12921 }
12922
12923 switch (a->action) {
12924 case GRN_ACCESSOR_GET_KEY :
12925 entry = GRN_HOOK_INSERT;
12926 break;
12927 case GRN_ACCESSOR_GET_COLUMN_VALUE :
12928 entry = GRN_HOOK_SET;
12929 break;
12930 default :
12931 break;
12932 }
12933
12934 if (entry == (grn_hook_entry)-1) {
12935 break;
12936 }
12937
12938 for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) {
12939 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
12940 grn_obj *target = grn_ctx_at(ctx, data->target);
12941
12942 if (target->header.type != GRN_COLUMN_INDEX) { continue; }
12943
12944 found = GRN_TRUE;
12945 if (!a->next) {
12946 int section;
12947
12948 if (!is_valid_index(ctx, target, op)) {
12949 continue;
12950 }
12951
12952 section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
12953 if (section_buf) {
12954 *section_buf = section;
12955 }
12956 if (n < buf_size) {
12957 *ip++ = target;
12958 }
12959 if (n < n_index_data) {
12960 index_data[n].index = target;
12961 index_data[n].section = section;
12962 }
12963 n++;
12964 }
12965 }
12966
12967 if (!found &&
12968 grn_column_find_index_data_accessor_is_key_search(ctx, a, op)) {
12969 grn_obj *index;
12970 int section = 0;
12971
12972 if ((grn_obj *)a == obj) {
12973 index = a->obj;
12974 } else {
12975 index = (grn_obj *)a;
12976 }
12977
12978 found = GRN_TRUE;
12979 if (section_buf) {
12980 *section_buf = section;
12981 }
12982 if (n < buf_size) {
12983 *ip++ = index;
12984 }
12985 if (n < n_index_data) {
12986 index_data[n].index = index;
12987 index_data[n].section = section;
12988 }
12989 n++;
12990 }
12991
12992 if (!found &&
12993 a->next &&
12994 grn_obj_is_table(ctx, a->obj) &&
12995 a->obj->header.domain == a->next->obj->header.domain) {
12996 grn_obj *index = (grn_obj *)a;
12997 int section = 0;
12998
12999 found = GRN_TRUE;
13000 if (section_buf) {
13001 *section_buf = section;
13002 }
13003 if (n < buf_size) {
13004 *ip++ = index;
13005 }
13006 if (n < n_index_data) {
13007 index_data[n].index = index;
13008 index_data[n].section = section;
13009 }
13010 n++;
13011 }
13012
13013 if (!found) {
13014 break;
13015 }
13016 a = a->next;
13017 }
13018
13019 return n;
13020}
13021
13022static int
13023grn_column_find_index_data_accessor(grn_ctx *ctx, grn_obj *obj,
13024 grn_operator op,
13025 grn_index_datum *index_data,
13026 unsigned n_index_data,
13027 grn_obj **index_buf, int buf_size,
13028 int *section_buf)
13029{
13030 int n = 0;
13031
13032 if (section_buf) {
13033 *section_buf = 0;
13034 }
13035 switch (op) {
13036 case GRN_OP_EQUAL :
13037 case GRN_OP_NOT_EQUAL :
13038 case GRN_OP_TERM_EXTRACT :
13039 if (buf_size > 0) {
13040 index_buf[n] = obj;
13041 }
13042 if (n_index_data > 0) {
13043 index_data[n].index = obj;
13044 index_data[n].section = 0;
13045 }
13046 n++;
13047 break;
13048 case GRN_OP_PREFIX :
13049 {
13050 grn_accessor *a = (grn_accessor *)obj;
13051 if (a->action == GRN_ACCESSOR_GET_KEY) {
13052 if (a->obj->header.type == GRN_TABLE_PAT_KEY) {
13053 if (buf_size > 0) {
13054 index_buf[n] = obj;
13055 }
13056 if (n_index_data > 0) {
13057 index_data[n].index = obj;
13058 index_data[n].section = 0;
13059 }
13060 n++;
13061 }
13062 /* FIXME: GRN_TABLE_DAT_KEY should be supported */
13063 }
13064 }
13065 break;
13066 case GRN_OP_SUFFIX :
13067 {
13068 grn_accessor *a = (grn_accessor *)obj;
13069 if (a->action == GRN_ACCESSOR_GET_KEY) {
13070 if (a->obj->header.type == GRN_TABLE_PAT_KEY &&
13071 a->obj->header.flags & GRN_OBJ_KEY_WITH_SIS) {
13072 if (buf_size > 0) {
13073 index_buf[n] = obj;
13074 }
13075 if (n_index_data > 0) {
13076 index_data[n].index = obj;
13077 index_data[n].section = 0;
13078 }
13079 n++;
13080 }
13081 }
13082 }
13083 break;
13084 case GRN_OP_MATCH :
13085 case GRN_OP_NEAR :
13086 case GRN_OP_NEAR2 :
13087 case GRN_OP_SIMILAR :
13088 case GRN_OP_LESS :
13089 case GRN_OP_GREATER :
13090 case GRN_OP_LESS_EQUAL :
13091 case GRN_OP_GREATER_EQUAL :
13092 case GRN_OP_CALL :
13093 case GRN_OP_REGEXP :
13094 case GRN_OP_FUZZY :
13095 n = grn_column_find_index_data_accessor_match(ctx, obj, op,
13096 index_data, n_index_data,
13097 index_buf, buf_size,
13098 section_buf);
13099 break;
13100 default :
13101 break;
13102 }
13103
13104 return n;
13105}
13106
13107int
13108grn_column_index(grn_ctx *ctx, grn_obj *obj, grn_operator op,
13109 grn_obj **index_buf, int buf_size, int *section_buf)
13110{
13111 int n = 0;
13112 GRN_API_ENTER;
13113 if (GRN_DB_OBJP(obj)) {
13114 switch (op) {
13115 case GRN_OP_EQUAL :
13116 case GRN_OP_NOT_EQUAL :
13117 n = grn_column_find_index_data_column_equal(ctx, obj, op,
13118 NULL, 0,
13119 index_buf, buf_size,
13120 section_buf);
13121 break;
13122 case GRN_OP_PREFIX :
13123 case GRN_OP_SUFFIX :
13124 case GRN_OP_MATCH :
13125 case GRN_OP_NEAR :
13126 case GRN_OP_NEAR2 :
13127 case GRN_OP_SIMILAR :
13128 case GRN_OP_REGEXP :
13129 case GRN_OP_FUZZY :
13130 n = grn_column_find_index_data_column_match(ctx, obj, op,
13131 NULL, 0,
13132 index_buf, buf_size,
13133 section_buf);
13134 break;
13135 case GRN_OP_LESS :
13136 case GRN_OP_GREATER :
13137 case GRN_OP_LESS_EQUAL :
13138 case GRN_OP_GREATER_EQUAL :
13139 case GRN_OP_CALL :
13140 n = grn_column_find_index_data_column_range(ctx, obj, op,
13141 NULL, 0,
13142 index_buf, buf_size,
13143 section_buf);
13144 break;
13145 default :
13146 break;
13147 }
13148 } else if (GRN_ACCESSORP(obj)) {
13149 n = grn_column_find_index_data_accessor(ctx, obj, op,
13150 NULL, 0,
13151 index_buf, buf_size,
13152 section_buf);
13153 }
13154 GRN_API_RETURN(n);
13155}
13156
13157unsigned int
13158grn_column_find_index_data(grn_ctx *ctx, grn_obj *obj, grn_operator op,
13159 grn_index_datum *index_data,
13160 unsigned int n_index_data)
13161{
13162 unsigned int n = 0;
13163 GRN_API_ENTER;
13164 if (GRN_DB_OBJP(obj)) {
13165 switch (op) {
13166 case GRN_OP_EQUAL :
13167 case GRN_OP_NOT_EQUAL :
13168 n = grn_column_find_index_data_column_equal(ctx, obj, op,
13169 index_data, n_index_data,
13170 NULL, 0, NULL);
13171 break;
13172 case GRN_OP_PREFIX :
13173 case GRN_OP_SUFFIX :
13174 case GRN_OP_MATCH :
13175 case GRN_OP_NEAR :
13176 case GRN_OP_NEAR2 :
13177 case GRN_OP_SIMILAR :
13178 case GRN_OP_REGEXP :
13179 case GRN_OP_FUZZY :
13180 n = grn_column_find_index_data_column_match(ctx, obj, op,
13181 index_data, n_index_data,
13182 NULL, 0, NULL);
13183 break;
13184 case GRN_OP_LESS :
13185 case GRN_OP_GREATER :
13186 case GRN_OP_LESS_EQUAL :
13187 case GRN_OP_GREATER_EQUAL :
13188 case GRN_OP_CALL :
13189 n = grn_column_find_index_data_column_range(ctx, obj, op,
13190 index_data, n_index_data,
13191 NULL, 0, NULL);
13192 break;
13193 default :
13194 break;
13195 }
13196 } else if (GRN_ACCESSORP(obj)) {
13197 n = grn_column_find_index_data_accessor(ctx, obj, op,
13198 index_data, n_index_data,
13199 NULL, 0, NULL);
13200 }
13201 GRN_API_RETURN(n);
13202}
13203
13204static uint32_t
13205grn_column_get_all_index_data_column(grn_ctx *ctx,
13206 grn_obj *obj,
13207 grn_index_datum *index_data,
13208 uint32_t n_index_data)
13209{
13210 uint32_t n = 0;
13211 grn_hook_entry hook_entry;
13212 grn_hook *hooks;
13213
13214 switch (obj->header.type) {
13215 case GRN_TABLE_HASH_KEY :
13216 case GRN_TABLE_PAT_KEY :
13217 case GRN_TABLE_DAT_KEY :
13218 case GRN_TABLE_NO_KEY :
13219 hook_entry = GRN_HOOK_INSERT;
13220 break;
13221 default :
13222 hook_entry = GRN_HOOK_SET;
13223 break;
13224 }
13225
13226 for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
13227 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
13228 grn_obj *target = grn_ctx_at(ctx, data->target);
13229 int section = 0;
13230 if (!target) {
13231 char name[GRN_TABLE_MAX_KEY_SIZE];
13232 int length;
13233 char hook_name[GRN_TABLE_MAX_KEY_SIZE];
13234 int hook_name_length;
13235
13236 length = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
13237 hook_name_length = grn_table_get_key(ctx,
13238 ctx->impl->db,
13239 data->target,
13240 hook_name,
13241 GRN_TABLE_MAX_KEY_SIZE);
13242 ERR(GRN_OBJECT_CORRUPT,
13243 "[column][indexes][all] "
13244 "hook has a dangling reference: <%.*s> -> <%.*s>",
13245 length, name,
13246 hook_name_length, hook_name);
13247 continue;
13248 }
13249 if (target->header.type != GRN_COLUMN_INDEX) {
13250 continue;
13251 }
13252 if (MULTI_COLUMN_INDEXP(target)) {
13253 section = data->section;
13254 }
13255 if (n < n_index_data) {
13256 index_data[n].index = target;
13257 index_data[n].section = section;
13258 }
13259 n++;
13260 }
13261
13262 return n;
13263}
13264
13265static uint32_t
13266grn_column_get_all_index_data_accessor_index_column(grn_ctx *ctx,
13267 grn_accessor *a,
13268 grn_index_datum *index_data,
13269 uint32_t n_index_data)
13270{
13271 grn_obj *index_column = a->obj;
13272 int section = 0;
13273
13274 if (a->next) {
13275 int specified_section;
13276 grn_bool is_invalid_section;
13277 if (a->next->next) {
13278 return 0;
13279 }
13280 specified_section = find_section(ctx, index_column, a->next->obj);
13281 is_invalid_section = (specified_section == 0);
13282 if (is_invalid_section) {
13283 return 0;
13284 }
13285 section = specified_section;
13286 }
13287 if (n_index_data > 0) {
13288 index_data[0].index = index_column;
13289 index_data[0].section = section;
13290 }
13291
13292 return 1;
13293}
13294
13295static uint32_t
13296grn_column_get_all_index_data_accessor(grn_ctx *ctx,
13297 grn_obj *obj,
13298 grn_index_datum *index_data,
13299 uint32_t n_index_data)
13300{
13301 uint32_t n = 0;
13302 grn_accessor *a = (grn_accessor *)obj;
13303
13304 while (a) {
13305 grn_hook *hooks;
13306 grn_bool found = GRN_FALSE;
13307 grn_hook_entry entry = (grn_hook_entry)-1;
13308
13309 if (a->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
13310 GRN_OBJ_INDEX_COLUMNP(a->obj)) {
13311 return grn_column_get_all_index_data_accessor_index_column(ctx,
13312 a,
13313 index_data,
13314 n_index_data);
13315 }
13316
13317 switch (a->action) {
13318 case GRN_ACCESSOR_GET_KEY :
13319 entry = GRN_HOOK_INSERT;
13320 break;
13321 case GRN_ACCESSOR_GET_COLUMN_VALUE :
13322 entry = GRN_HOOK_SET;
13323 break;
13324 default :
13325 break;
13326 }
13327
13328 if (entry == (grn_hook_entry)-1) {
13329 break;
13330 }
13331
13332 for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) {
13333 grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
13334 grn_obj *target = grn_ctx_at(ctx, data->target);
13335
13336 if (target->header.type != GRN_COLUMN_INDEX) {
13337 continue;
13338 }
13339
13340 found = GRN_TRUE;
13341 if (!a->next) {
13342 int section = 0;
13343
13344 if (MULTI_COLUMN_INDEXP(target)) {
13345 section = data->section;
13346 }
13347 if (n < n_index_data) {
13348 index_data[n].index = target;
13349 index_data[n].section = section;
13350 }
13351 n++;
13352 }
13353 }
13354
13355 if (!found) {
13356 break;
13357 }
13358 a = a->next;
13359 }
13360
13361 return n;
13362}
13363
13364uint32_t
13365grn_column_get_all_index_data(grn_ctx *ctx,
13366 grn_obj *obj,
13367 grn_index_datum *index_data,
13368 uint32_t n_index_data)
13369{
13370 uint32_t n = 0;
13371 GRN_API_ENTER;
13372 if (GRN_DB_OBJP(obj)) {
13373 n = grn_column_get_all_index_data_column(ctx, obj,
13374 index_data, n_index_data);
13375 } else if (GRN_ACCESSORP(obj)) {
13376 n = grn_column_get_all_index_data_accessor(ctx, obj,
13377 index_data, n_index_data);
13378 }
13379 GRN_API_RETURN(n);
13380}
13381
13382grn_rc
13383grn_obj_columns(grn_ctx *ctx, grn_obj *table,
13384 const char *str, unsigned int str_size, grn_obj *res)
13385{
13386 grn_obj *col;
13387 const char *p = (char *)str, *q, *r, *pe = p + str_size, *tokbuf[256];
13388 while (p < pe) {
13389 int i, n = grn_tokenize(p, pe - p, tokbuf, 256, &q);
13390 for (i = 0; i < n; i++) {
13391 r = tokbuf[i];
13392 while (p < r && (' ' == *p || ',' == *p)) { p++; }
13393 if (p < r) {
13394 if (r[-1] == '*') {
13395 grn_hash *cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
13396 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
13397 if (cols) {
13398 grn_id *key;
13399 grn_table_columns(ctx, table, p, r - p - 1, (grn_obj *)cols);
13400 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
13401 if ((col = grn_ctx_at(ctx, *key))) { GRN_PTR_PUT(ctx, res, col); }
13402 });
13403 grn_hash_close(ctx, cols);
13404 }
13405 {
13406 grn_obj *type = grn_ctx_at(ctx, table->header.domain);
13407 if (GRN_OBJ_TABLEP(type)) {
13408 grn_obj *ai = grn_obj_column(ctx, table,
13409 GRN_COLUMN_NAME_ID,
13410 GRN_COLUMN_NAME_ID_LEN);
13411 if (ai) {
13412 if (ai->header.type == GRN_ACCESSOR) {
13413 grn_id *key;
13414 grn_accessor *id_accessor;
13415 for (id_accessor = ((grn_accessor *)ai)->next;
13416 id_accessor;
13417 id_accessor = id_accessor->next) {
13418 grn_obj *target_table = id_accessor->obj;
13419
13420 cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
13421 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
13422 if (!cols) {
13423 continue;
13424 }
13425 grn_table_columns(ctx, target_table,
13426 p, r - p - 1, (grn_obj *)cols);
13427 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
13428 if ((col = grn_ctx_at(ctx, *key))) {
13429 grn_accessor *a;
13430 grn_accessor *ac;
13431 ac = accessor_new(ctx);
13432 GRN_PTR_PUT(ctx, res, (grn_obj *)ac);
13433 for (a = (grn_accessor *)ai; a; a = a->next) {
13434 if (a->action != GRN_ACCESSOR_GET_ID) {
13435 ac->action = a->action;
13436 ac->obj = a->obj;
13437 ac->next = accessor_new(ctx);
13438 if (!(ac = ac->next)) { break; }
13439 } else {
13440 ac->action = GRN_ACCESSOR_GET_COLUMN_VALUE;
13441 ac->obj = col;
13442 ac->next = NULL;
13443 break;
13444 }
13445 }
13446 }
13447 });
13448 grn_hash_close(ctx, cols);
13449 }
13450 }
13451 grn_obj_unlink(ctx, ai);
13452 }
13453 }
13454 }
13455 } else if ((col = grn_obj_column(ctx, table, p, r - p))) {
13456 GRN_PTR_PUT(ctx, res, col);
13457 }
13458 }
13459 p = r;
13460 }
13461 p = q;
13462 }
13463 return ctx->rc;
13464}
13465
13466static grn_table_sort_key *
13467grn_table_sort_key_from_str_geo(grn_ctx *ctx, const char *str, unsigned int str_size,
13468 grn_obj *table, unsigned int *nkeys)
13469{
13470 const char **tokbuf;
13471 const char *p = str, *pe = str + str_size;
13472 grn_table_sort_key *keys = NULL, *k = NULL;
13473 while ((*p++ != '(')) { if (p == pe) { return NULL; } }
13474 str = p;
13475 while ((*p != ')')) { if (++p == pe) { return NULL; } }
13476 str_size = p - str;
13477 p = str;
13478 if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
13479 grn_id domain = GRN_ID_NIL;
13480 int i, n = grn_tokenize(str, str_size, tokbuf, str_size, NULL);
13481 if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
13482 k = keys;
13483 for (i = 0; i < n; i++) {
13484 const char *r = tokbuf[i];
13485 while (p < r && (' ' == *p || ',' == *p)) { p++; }
13486 if (p < r) {
13487 k->flags = GRN_TABLE_SORT_ASC;
13488 k->offset = 0;
13489 if (*p == '+') {
13490 p++;
13491 } else if (*p == '-') {
13492 k->flags = GRN_TABLE_SORT_DESC;
13493 p++;
13494 }
13495 if (k == keys) {
13496 if (!(k->key = grn_obj_column(ctx, table, p, r - p))) {
13497 WARN(GRN_INVALID_ARGUMENT, "invalid sort key: <%.*s>(<%.*s>)",
13498 (int)(tokbuf[i] - p), p, str_size, str);
13499 break;
13500 }
13501 domain = grn_obj_get_range(ctx, k->key);
13502 } else {
13503 grn_obj buf;
13504 GRN_TEXT_INIT(&buf, GRN_OBJ_DO_SHALLOW_COPY);
13505 GRN_TEXT_SET(ctx, &buf, p + 1, r - p - 2); /* should be quoted */
13506 k->key = grn_obj_open(ctx, GRN_BULK, 0, domain);
13507 grn_obj_cast(ctx, &buf, k->key, GRN_FALSE);
13508 GRN_OBJ_FIN(ctx, &buf);
13509 }
13510 k->flags |= GRN_TABLE_SORT_GEO;
13511 k++;
13512 }
13513 p = r;
13514 }
13515 }
13516 GRN_FREE(tokbuf);
13517 }
13518 if (!ctx->rc && k - keys > 0) {
13519 *nkeys = k - keys;
13520 } else {
13521 grn_table_sort_key_close(ctx, keys, k - keys);
13522 *nkeys = 0;
13523 keys = NULL;
13524 }
13525 return keys;
13526}
13527
13528grn_table_sort_key *
13529grn_table_sort_key_from_str(grn_ctx *ctx, const char *str, unsigned int str_size,
13530 grn_obj *table, unsigned int *nkeys)
13531{
13532 const char *p = str;
13533 const char **tokbuf;
13534 grn_table_sort_key *keys = NULL, *k = NULL;
13535
13536 if (str_size == 0) {
13537 return NULL;
13538 }
13539
13540 if ((keys = grn_table_sort_key_from_str_geo(ctx, str, str_size, table, nkeys))) {
13541 return keys;
13542 }
13543 if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
13544 int i, n = grn_tokenize(str, str_size, tokbuf, str_size, NULL);
13545 if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
13546 k = keys;
13547 for (i = 0; i < n; i++) {
13548 const char *r = tokbuf[i];
13549 while (p < r && (' ' == *p || ',' == *p)) { p++; }
13550 if (p < r) {
13551 k->flags = GRN_TABLE_SORT_ASC;
13552 k->offset = 0;
13553 if (*p == '+') {
13554 p++;
13555 } else if (*p == '-') {
13556 k->flags = GRN_TABLE_SORT_DESC;
13557 p++;
13558 }
13559 if ((k->key = grn_obj_column(ctx, table, p, r - p))) {
13560 k++;
13561 } else {
13562 if (r - p == GRN_COLUMN_NAME_SCORE_LEN &&
13563 memcmp(p, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN) == 0) {
13564 char table_name[GRN_TABLE_MAX_KEY_SIZE];
13565 int table_name_size;
13566 table_name_size = grn_obj_name(ctx, table,
13567 table_name,
13568 GRN_TABLE_MAX_KEY_SIZE);
13569 if (table_name_size == 0) {
13570 grn_strcpy(table_name, GRN_TABLE_MAX_KEY_SIZE, "(anonymous)");
13571 table_name_size = strlen(table_name);
13572 }
13573 GRN_LOG(ctx, GRN_WARN,
13574 "ignore invalid sort key: <%.*s>: "
13575 "table:<%*.s> keys:<%.*s>",
13576 (int)(r - p), p,
13577 table_name_size, table_name,
13578 str_size, str);
13579 } else {
13580 char table_name[GRN_TABLE_MAX_KEY_SIZE];
13581 int table_name_size;
13582 table_name_size = grn_obj_name(ctx, table,
13583 table_name,
13584 GRN_TABLE_MAX_KEY_SIZE);
13585 if (table_name_size == 0) {
13586 grn_strcpy(table_name, GRN_TABLE_MAX_KEY_SIZE, "(anonymous)");
13587 table_name_size = strlen(table_name);
13588 }
13589 WARN(GRN_INVALID_ARGUMENT,
13590 "invalid sort key: <%.*s>: "
13591 "table:<%.*s> keys:<%.*s>",
13592 (int)(r - p), p,
13593 table_name_size, table_name,
13594 str_size, str);
13595 break;
13596 }
13597 }
13598 }
13599 p = r;
13600 }
13601 }
13602 GRN_FREE(tokbuf);
13603 }
13604 if (!ctx->rc && k - keys > 0) {
13605 *nkeys = k - keys;
13606 } else {
13607 grn_table_sort_key_close(ctx, keys, k - keys);
13608 *nkeys = 0;
13609 keys = NULL;
13610 }
13611 return keys;
13612}
13613
13614grn_rc
13615grn_table_sort_key_close(grn_ctx *ctx, grn_table_sort_key *keys, unsigned int nkeys)
13616{
13617 int i;
13618 if (keys) {
13619 for (i = 0; i < nkeys; i++) {
13620 grn_obj *key = keys[i].key;
13621 if (!grn_obj_is_column(ctx, key)) {
13622 grn_obj_unlink(ctx, key);
13623 }
13624 }
13625 GRN_FREE(keys);
13626 }
13627 return ctx->rc;
13628}
13629
13630grn_bool
13631grn_table_is_grouped(grn_ctx *ctx, grn_obj *table)
13632{
13633 if (GRN_OBJ_TABLEP(table) && GRN_TABLE_IS_GROUPED(table)) {
13634 return GRN_TRUE;
13635 }
13636 return GRN_FALSE;
13637}
13638
13639unsigned int
13640grn_table_max_n_subrecs(grn_ctx *ctx, grn_obj *table)
13641{
13642 if (GRN_OBJ_TABLEP(table)) {
13643 return DB_OBJ(table)->max_n_subrecs;
13644 }
13645 return 0;
13646}
13647
13648grn_obj *
13649grn_table_tokenize(grn_ctx *ctx, grn_obj *table,
13650 const char *str, unsigned int str_len,
13651 grn_obj *buf, grn_bool addp)
13652{
13653 grn_token_cursor *token_cursor = NULL;
13654 grn_tokenize_mode mode = addp ? GRN_TOKENIZE_ADD : GRN_TOKENIZE_GET;
13655 GRN_API_ENTER;
13656 if (!(token_cursor = grn_token_cursor_open(ctx, table, str, str_len, mode, 0))) {
13657 goto exit;
13658 }
13659 if (buf) {
13660 GRN_BULK_REWIND(buf);
13661 } else {
13662 if (!(buf = grn_obj_open(ctx, GRN_UVECTOR, 0, DB_OBJ(table)->id))) {
13663 goto exit;
13664 }
13665 }
13666 while (token_cursor->status != GRN_TOKEN_CURSOR_DONE && token_cursor->status != GRN_TOKEN_CURSOR_DONE_SKIP) {
13667 grn_id tid;
13668 if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
13669 GRN_RECORD_PUT(ctx, buf, tid);
13670 }
13671 }
13672exit :
13673 if (token_cursor) {
13674 grn_token_cursor_close(ctx, token_cursor);
13675 }
13676 GRN_API_RETURN(buf);
13677}
13678
13679static void
13680grn_db_recover_database_remove_orphan_inspect(grn_ctx *ctx, grn_obj *db)
13681{
13682 GRN_TABLE_EACH_BEGIN_FLAGS(ctx, db, cursor, id, GRN_CURSOR_BY_ID) {
13683 void *key;
13684 int key_size;
13685
13686 key_size = grn_table_cursor_get_key(ctx, cursor, &key);
13687#define INSPECT "inspect"
13688#define INSPECT_LEN (sizeof(INSPECT) - 1)
13689 if (key_size == INSPECT_LEN && memcmp(key, INSPECT, INSPECT_LEN) == 0) {
13690 if (!grn_ctx_at(ctx, id)) {
13691 ERRCLR(ctx);
13692 grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
13693 }
13694 break;
13695 }
13696#undef INSPECT
13697#undef INSPECT_LEN
13698 } GRN_TABLE_EACH_END(ctx, cursor);
13699}
13700
13701static void
13702grn_db_recover_database(grn_ctx *ctx, grn_obj *db)
13703{
13704 if (grn_obj_is_locked(ctx, db)) {
13705 ERR(GRN_OBJECT_CORRUPT,
13706 "[db][recover] database may be broken. Please re-create the database");
13707 return;
13708 }
13709
13710 grn_db_clear_dirty(ctx, db);
13711 grn_db_recover_database_remove_orphan_inspect(ctx, db);
13712}
13713
13714static void
13715grn_db_recover_table(grn_ctx *ctx, grn_obj *table)
13716{
13717 if (!grn_obj_is_locked(ctx, table)) {
13718 return;
13719 }
13720
13721 {
13722 char name[GRN_TABLE_MAX_KEY_SIZE];
13723 unsigned int name_size;
13724 name_size = grn_obj_name(ctx, table, name, GRN_TABLE_MAX_KEY_SIZE);
13725 ERR(GRN_OBJECT_CORRUPT,
13726 "[db][recover] table may be broken: <%.*s>: "
13727 "please truncate the table (or clear lock of the table) "
13728 "and load data again",
13729 (int)name_size, name);
13730 }
13731}
13732
13733static void
13734grn_db_recover_data_column(grn_ctx *ctx, grn_obj *data_column)
13735{
13736 if (!grn_obj_is_locked(ctx, data_column)) {
13737 return;
13738 }
13739
13740 {
13741 char name[GRN_TABLE_MAX_KEY_SIZE];
13742 unsigned int name_size;
13743 name_size = grn_obj_name(ctx, data_column, name, GRN_TABLE_MAX_KEY_SIZE);
13744 ERR(GRN_OBJECT_CORRUPT,
13745 "[db][recover] column may be broken: <%.*s>: "
13746 "please truncate the column (or clear lock of the column) "
13747 "and load data again",
13748 (int)name_size, name);
13749 }
13750}
13751
13752static void
13753grn_db_recover_index_column(grn_ctx *ctx, grn_obj *index_column)
13754{
13755 if (!grn_obj_is_locked(ctx, index_column)) {
13756 return;
13757 }
13758
13759 grn_index_column_rebuild(ctx, index_column);
13760}
13761
13762static grn_bool
13763grn_db_recover_is_builtin(grn_ctx *ctx, grn_id id, grn_table_cursor *cursor)
13764{
13765 void *key;
13766 const char *name;
13767 int name_size;
13768
13769 if (id < GRN_N_RESERVED_TYPES) {
13770 return GRN_TRUE;
13771 }
13772
13773 name_size = grn_table_cursor_get_key(ctx, cursor, &key);
13774 name = key;
13775
13776#define NAME_EQUAL(value) \
13777 (name_size == strlen(value) && memcmp(name, value, strlen(value)) == 0)
13778
13779 if (NAME_EQUAL("inspect")) {
13780 /* Just for compatibility. It's needed for users who used
13781 Groonga master at between 2016-02-03 and 2016-02-26. */
13782 return GRN_TRUE;
13783 }
13784
13785#undef NAME_EQUAL
13786
13787 return GRN_FALSE;
13788}
13789
13790grn_rc
13791grn_db_recover(grn_ctx *ctx, grn_obj *db)
13792{
13793 grn_table_cursor *cursor;
13794 grn_id id;
13795 grn_bool is_close_opened_object_mode;
13796
13797 GRN_API_ENTER;
13798
13799 is_close_opened_object_mode = (grn_thread_get_limit() == 1);
13800
13801 grn_db_recover_database(ctx, db);
13802 if (ctx->rc != GRN_SUCCESS) {
13803 GRN_API_RETURN(ctx->rc);
13804 }
13805
13806 cursor = grn_table_cursor_open(ctx, db,
13807 NULL, 0, NULL, 0,
13808 0, -1,
13809 GRN_CURSOR_BY_ID);
13810 if (!cursor) {
13811 GRN_API_RETURN(ctx->rc);
13812 }
13813
13814 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
13815 grn_obj *object;
13816
13817 if (is_close_opened_object_mode) {
13818 grn_ctx_push_temporary_open_space(ctx);
13819 }
13820
13821 if ((object = grn_ctx_at(ctx, id))) {
13822 switch (object->header.type) {
13823 case GRN_TABLE_NO_KEY :
13824 case GRN_TABLE_HASH_KEY :
13825 case GRN_TABLE_PAT_KEY :
13826 case GRN_TABLE_DAT_KEY :
13827 grn_db_recover_table(ctx, object);
13828 break;
13829 case GRN_COLUMN_FIX_SIZE :
13830 case GRN_COLUMN_VAR_SIZE :
13831 grn_db_recover_data_column(ctx, object);
13832 break;
13833 case GRN_COLUMN_INDEX :
13834 grn_db_recover_index_column(ctx, object);
13835 break;
13836 default:
13837 break;
13838 }
13839 grn_obj_unlink(ctx, object);
13840 } else {
13841 if (grn_db_recover_is_builtin(ctx, id, cursor)) {
13842 ERRCLR(ctx);
13843 }
13844 }
13845
13846 if (is_close_opened_object_mode) {
13847 grn_ctx_pop_temporary_open_space(ctx);
13848 }
13849
13850 if (ctx->rc != GRN_SUCCESS) {
13851 break;
13852 }
13853 }
13854 grn_table_cursor_close(ctx, cursor);
13855
13856 GRN_API_RETURN(ctx->rc);
13857}
13858
13859grn_rc
13860grn_db_unmap(grn_ctx *ctx, grn_obj *db)
13861{
13862 grn_id id;
13863 db_value *vp;
13864 grn_db *s = (grn_db *)db;
13865
13866 GRN_API_ENTER;
13867
13868 GRN_TINY_ARRAY_EACH(&s->values, 1, grn_db_curr_id(ctx, db), id, vp, {
13869 grn_obj *obj = vp->ptr;
13870
13871 if (obj) {
13872 switch (obj->header.type) {
13873 case GRN_TABLE_HASH_KEY :
13874 case GRN_TABLE_PAT_KEY :
13875 case GRN_TABLE_DAT_KEY :
13876 case GRN_TABLE_NO_KEY :
13877 case GRN_COLUMN_FIX_SIZE :
13878 case GRN_COLUMN_VAR_SIZE :
13879 case GRN_COLUMN_INDEX :
13880 grn_obj_close(ctx, obj);
13881 break;
13882 }
13883 }
13884 });
13885
13886 GRN_API_RETURN(ctx->rc);
13887}
13888
13889static grn_rc
13890grn_ctx_get_all_objects(grn_ctx *ctx, grn_obj *objects_buffer,
13891 grn_bool (*predicate)(grn_ctx *ctx, grn_obj *object))
13892{
13893 grn_obj *db;
13894 grn_table_cursor *cursor;
13895 grn_id id;
13896
13897 GRN_API_ENTER;
13898
13899 db = ctx->impl->db;
13900 if (!db) {
13901 ERR(GRN_INVALID_ARGUMENT, "DB isn't associated");
13902 GRN_API_RETURN(ctx->rc);
13903 }
13904
13905 cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0);
13906 if (!cursor) {
13907 GRN_API_RETURN(ctx->rc);
13908 }
13909
13910 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
13911 grn_obj *object;
13912
13913 if ((object = grn_ctx_at(ctx, id))) {
13914 if (predicate(ctx, object)) {
13915 GRN_PTR_PUT(ctx, objects_buffer, object);
13916 } else {
13917 grn_obj_unlink(ctx, object);
13918 }
13919 } else {
13920 if (ctx->rc != GRN_SUCCESS) {
13921 ERRCLR(ctx);
13922 }
13923 }
13924 }
13925 grn_table_cursor_close(ctx, cursor);
13926
13927 GRN_API_RETURN(ctx->rc);
13928}
13929
13930grn_rc
13931grn_ctx_get_all_tables(grn_ctx *ctx, grn_obj *tables_buffer)
13932{
13933 return grn_ctx_get_all_objects(ctx, tables_buffer, grn_obj_is_table);
13934}
13935
13936grn_rc
13937grn_ctx_get_all_types(grn_ctx *ctx, grn_obj *types_buffer)
13938{
13939 return grn_ctx_get_all_objects(ctx, types_buffer, grn_obj_is_type);
13940}
13941
13942grn_rc
13943grn_ctx_get_all_tokenizers(grn_ctx *ctx, grn_obj *tokenizers_buffer)
13944{
13945 return grn_ctx_get_all_objects(ctx, tokenizers_buffer,
13946 grn_obj_is_tokenizer_proc);
13947}
13948
13949grn_rc
13950grn_ctx_get_all_normalizers(grn_ctx *ctx, grn_obj *normalizers_buffer)
13951{
13952 return grn_ctx_get_all_objects(ctx, normalizers_buffer,
13953 grn_obj_is_normalizer_proc);
13954}
13955
13956grn_rc
13957grn_ctx_get_all_token_filters(grn_ctx *ctx, grn_obj *token_filters_buffer)
13958{
13959 return grn_ctx_get_all_objects(ctx, token_filters_buffer,
13960 grn_obj_is_token_filter_proc);
13961}
13962
13963grn_rc
13964grn_ctx_push_temporary_open_space(grn_ctx *ctx)
13965{
13966 grn_obj *stack;
13967 grn_obj *space;
13968 grn_obj buffer;
13969
13970 GRN_API_ENTER;
13971
13972 stack = &(ctx->impl->temporary_open_spaces.stack);
13973 GRN_VOID_INIT(&buffer);
13974 grn_bulk_write(ctx, stack, (const char *)&buffer, sizeof(grn_obj));
13975 space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
13976 GRN_PTR_INIT(space, GRN_OBJ_VECTOR | GRN_OBJ_OWN, GRN_ID_NIL);
13977
13978 ctx->impl->temporary_open_spaces.current = space;
13979
13980 GRN_API_RETURN(ctx->rc);
13981}
13982
13983grn_rc
13984grn_ctx_pop_temporary_open_space(grn_ctx *ctx)
13985{
13986 grn_obj *stack;
13987 grn_obj *space;
13988
13989 GRN_API_ENTER;
13990
13991 stack = &(ctx->impl->temporary_open_spaces.stack);
13992 if (GRN_BULK_EMPTYP(stack)) {
13993 ERR(GRN_INVALID_ARGUMENT,
13994 "[ctx][temporary-open-spaces][pop] too much pop");
13995 GRN_API_RETURN(ctx->rc);
13996 }
13997
13998 space = ctx->impl->temporary_open_spaces.current;
13999 GRN_OBJ_FIN(ctx, space);
14000 grn_bulk_truncate(ctx, stack, GRN_BULK_VSIZE(stack) - sizeof(grn_obj));
14001
14002 if (GRN_BULK_EMPTYP(stack)) {
14003 space = NULL;
14004 } else {
14005 space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
14006 }
14007 ctx->impl->temporary_open_spaces.current = space;
14008
14009 GRN_API_RETURN(ctx->rc);
14010}
14011
14012grn_rc
14013grn_ctx_merge_temporary_open_space(grn_ctx *ctx)
14014{
14015 grn_obj *stack;
14016 grn_obj *space;
14017 grn_obj *next_space;
14018
14019 GRN_API_ENTER;
14020
14021 stack = &(ctx->impl->temporary_open_spaces.stack);
14022 if (GRN_BULK_VSIZE(stack) < sizeof(grn_obj) * 2) {
14023 ERR(GRN_INVALID_ARGUMENT,
14024 "[ctx][temporary-open-spaces][merge] "
14025 "merge requires at least two spaces");
14026 GRN_API_RETURN(ctx->rc);
14027 }
14028
14029 space = ctx->impl->temporary_open_spaces.current;
14030 next_space = ctx->impl->temporary_open_spaces.current - 1;
14031 {
14032 unsigned int i, n_elements;
14033 n_elements = GRN_BULK_VSIZE(space) / sizeof(grn_obj *);
14034 for (i = 0; i < n_elements; i++) {
14035 grn_obj *element = GRN_PTR_VALUE_AT(space, i);
14036 GRN_PTR_PUT(ctx, next_space, element);
14037 }
14038 }
14039 GRN_BULK_REWIND(space);
14040 GRN_OBJ_FIN(ctx, space);
14041 grn_bulk_truncate(ctx, stack, GRN_BULK_VSIZE(stack) - sizeof(grn_obj));
14042
14043 if (GRN_BULK_EMPTYP(stack)) {
14044 space = NULL;
14045 } else {
14046 space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
14047 }
14048 ctx->impl->temporary_open_spaces.current = space;
14049
14050 GRN_API_RETURN(ctx->rc);
14051}
14052