1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2009-2016 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "../grn_proc.h"
20
21#include "../grn_ctx.h"
22#include "../grn_str.h"
23#include "../grn_db.h"
24
25#include <groonga/plugin.h>
26
27static grn_table_flags
28command_table_create_parse_flags(grn_ctx *ctx,
29 const char *nptr,
30 const char *end)
31{
32 grn_table_flags flags = 0;
33 while (nptr < end) {
34 size_t name_size;
35
36 if (*nptr == '|' || *nptr == ' ') {
37 nptr += 1;
38 continue;
39 }
40
41#define CHECK_FLAG(name) \
42 name_size = strlen(#name); \
43 if ((end - nptr) >= name_size && \
44 memcmp(nptr, #name, name_size) == 0) { \
45 flags |= GRN_OBJ_ ## name; \
46 nptr += name_size; \
47 continue; \
48 }
49
50 CHECK_FLAG(TABLE_HASH_KEY);
51 CHECK_FLAG(TABLE_PAT_KEY);
52 CHECK_FLAG(TABLE_DAT_KEY);
53 CHECK_FLAG(TABLE_NO_KEY);
54 CHECK_FLAG(KEY_NORMALIZE);
55 CHECK_FLAG(KEY_WITH_SIS);
56 CHECK_FLAG(KEY_LARGE);
57
58#undef CHECK_FLAG
59
60 GRN_PLUGIN_ERROR(ctx,
61 GRN_INVALID_ARGUMENT,
62 "[table][create][flags] unknown flag: <%.*s>",
63 (int)(end - nptr), nptr);
64 return 0;
65 }
66 return flags;
67}
68
69static grn_bool
70grn_proc_table_set_token_filters_put(grn_ctx *ctx,
71 grn_obj *token_filters,
72 const char *token_filter_name,
73 int token_filter_name_length)
74{
75 grn_obj *token_filter;
76
77 token_filter = grn_ctx_get(ctx,
78 token_filter_name,
79 token_filter_name_length);
80 if (token_filter) {
81 GRN_PTR_PUT(ctx, token_filters, token_filter);
82 return GRN_TRUE;
83 } else {
84 GRN_PLUGIN_ERROR(ctx,
85 GRN_INVALID_ARGUMENT,
86 "[table][create][token-filter] "
87 "nonexistent token filter: <%.*s>",
88 token_filter_name_length, token_filter_name);
89 return GRN_FALSE;
90 }
91}
92
93static grn_bool
94grn_proc_table_set_token_filters_fill(grn_ctx *ctx,
95 grn_obj *token_filters,
96 grn_obj *token_filter_names)
97{
98 const char *start, *current, *end;
99 const char *name_start, *name_end;
100 const char *last_name_end;
101
102 start = GRN_TEXT_VALUE(token_filter_names);
103 end = start + GRN_TEXT_LEN(token_filter_names);
104 current = start;
105 name_start = NULL;
106 name_end = NULL;
107 last_name_end = start;
108 while (current < end) {
109 switch (current[0]) {
110 case ' ' :
111 if (name_start && !name_end) {
112 name_end = current;
113 }
114 break;
115 case ',' :
116 if (!name_start) {
117 goto break_loop;
118 }
119 if (!name_end) {
120 name_end = current;
121 }
122 if (!grn_proc_table_set_token_filters_put(ctx,
123 token_filters,
124 name_start,
125 name_end - name_start)) {
126 return GRN_FALSE;
127 }
128 last_name_end = name_end + 1;
129 name_start = NULL;
130 name_end = NULL;
131 break;
132 default :
133 if (!name_start) {
134 name_start = current;
135 }
136 break;
137 }
138 current++;
139 }
140
141break_loop:
142 if (!name_start) {
143 GRN_PLUGIN_ERROR(ctx,
144 GRN_INVALID_ARGUMENT,
145 "[table][create][token-filter] empty token filter name: "
146 "<%.*s|%.*s|%.*s>",
147 (int)(last_name_end - start), start,
148 (int)(current - last_name_end), last_name_end,
149 (int)(end - current), current);
150 return GRN_FALSE;
151 }
152
153 if (!name_end) {
154 name_end = current;
155 }
156 grn_proc_table_set_token_filters_put(ctx,
157 token_filters,
158 name_start,
159 name_end - name_start);
160
161 return GRN_TRUE;
162}
163
164grn_bool
165grn_proc_table_set_token_filters(grn_ctx *ctx,
166 grn_obj *table,
167 grn_obj *token_filter_names)
168{
169 grn_bool succeeded = GRN_FALSE;
170 grn_obj token_filters;
171
172 if (GRN_TEXT_LEN(token_filter_names) == 0) {
173 return GRN_TRUE;
174 }
175
176 GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
177 succeeded = grn_proc_table_set_token_filters_fill(ctx,
178 &token_filters,
179 token_filter_names);
180 if (succeeded) {
181 grn_obj_set_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
182 }
183 grn_obj_unlink(ctx, &token_filters);
184
185 return succeeded;
186}
187
188static grn_obj *
189command_table_create(grn_ctx *ctx,
190 int nargs,
191 grn_obj **args,
192 grn_user_data *user_data)
193{
194 grn_obj *name;
195 grn_obj *flags_raw;
196 grn_obj *key_type_name;
197 grn_obj *value_type_name;
198 grn_obj *default_tokenizer_name;
199 grn_obj *normalizer_name;
200 grn_obj *token_filters_name;
201 grn_obj *table;
202 const char *rest;
203 grn_table_flags flags;
204
205 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
206 flags_raw = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
207 key_type_name = grn_plugin_proc_get_var(ctx, user_data, "key_type", -1);
208 value_type_name = grn_plugin_proc_get_var(ctx, user_data, "value_type", -1);
209 default_tokenizer_name =
210 grn_plugin_proc_get_var(ctx, user_data, "default_tokenizer", -1);
211 normalizer_name =
212 grn_plugin_proc_get_var(ctx, user_data, "normalizer", -1);
213 token_filters_name =
214 grn_plugin_proc_get_var(ctx, user_data, "token_filters", -1);
215
216 flags = grn_atoi(GRN_TEXT_VALUE(flags_raw),
217 GRN_BULK_CURR(flags_raw),
218 &rest);
219
220 if (GRN_TEXT_VALUE(flags_raw) == rest) {
221 flags = command_table_create_parse_flags(ctx,
222 GRN_TEXT_VALUE(flags_raw),
223 GRN_BULK_CURR(flags_raw));
224 if (ctx->rc) { goto exit; }
225 }
226
227 if (GRN_TEXT_LEN(name) == 0) {
228 GRN_PLUGIN_ERROR(ctx,
229 GRN_INVALID_ARGUMENT,
230 "[table][create] should not create anonymous table");
231 goto exit;
232 }
233
234 {
235 grn_obj *key_type = NULL;
236 grn_obj *value_type = NULL;
237
238 if (GRN_TEXT_LEN(key_type_name) > 0) {
239 key_type = grn_ctx_get(ctx,
240 GRN_TEXT_VALUE(key_type_name),
241 GRN_TEXT_LEN(key_type_name));
242 if (!key_type) {
243 GRN_PLUGIN_ERROR(ctx,
244 GRN_INVALID_ARGUMENT,
245 "[table][create] "
246 "key type doesn't exist: <%.*s> (%.*s)",
247 (int)GRN_TEXT_LEN(name),
248 GRN_TEXT_VALUE(name),
249 (int)GRN_TEXT_LEN(key_type_name),
250 GRN_TEXT_VALUE(key_type_name));
251 goto exit;
252 }
253 }
254
255 if (GRN_TEXT_LEN(value_type_name) > 0) {
256 value_type = grn_ctx_get(ctx,
257 GRN_TEXT_VALUE(value_type_name),
258 GRN_TEXT_LEN(value_type_name));
259 if (!value_type) {
260 GRN_PLUGIN_ERROR(ctx,
261 GRN_INVALID_ARGUMENT,
262 "[table][create] "
263 "value type doesn't exist: <%.*s> (%.*s)",
264 (int)GRN_TEXT_LEN(name),
265 GRN_TEXT_VALUE(name),
266 (int)GRN_TEXT_LEN(value_type_name),
267 GRN_TEXT_VALUE(value_type_name));
268 goto exit;
269 }
270 }
271
272 flags |= GRN_OBJ_PERSISTENT;
273 table = grn_table_create(ctx,
274 GRN_TEXT_VALUE(name),
275 GRN_TEXT_LEN(name),
276 NULL, flags,
277 key_type,
278 value_type);
279 if (!table) {
280 goto exit;
281 }
282
283 if (GRN_TEXT_LEN(default_tokenizer_name) > 0) {
284 grn_obj *default_tokenizer;
285
286 default_tokenizer =
287 grn_ctx_get(ctx,
288 GRN_TEXT_VALUE(default_tokenizer_name),
289 GRN_TEXT_LEN(default_tokenizer_name));
290 if (!default_tokenizer) {
291 GRN_PLUGIN_ERROR(ctx,
292 GRN_INVALID_ARGUMENT,
293 "[table][create][%.*s] unknown tokenizer: <%.*s>",
294 (int)GRN_TEXT_LEN(name),
295 GRN_TEXT_VALUE(name),
296 (int)GRN_TEXT_LEN(default_tokenizer_name),
297 GRN_TEXT_VALUE(default_tokenizer_name));
298 grn_obj_remove(ctx, table);
299 goto exit;
300 }
301 grn_obj_set_info(ctx, table,
302 GRN_INFO_DEFAULT_TOKENIZER,
303 default_tokenizer);
304 }
305
306 if (GRN_TEXT_LEN(normalizer_name) > 0) {
307 grn_obj *normalizer;
308
309 normalizer =
310 grn_ctx_get(ctx,
311 GRN_TEXT_VALUE(normalizer_name),
312 GRN_TEXT_LEN(normalizer_name));
313 if (!normalizer) {
314 GRN_PLUGIN_ERROR(ctx,
315 GRN_INVALID_ARGUMENT,
316 "[table][create][%.*s] unknown normalizer: <%.*s>",
317 (int)GRN_TEXT_LEN(name),
318 GRN_TEXT_VALUE(name),
319 (int)GRN_TEXT_LEN(normalizer_name),
320 GRN_TEXT_VALUE(normalizer_name));
321 grn_obj_remove(ctx, table);
322 goto exit;
323 }
324 grn_obj_set_info(ctx, table, GRN_INFO_NORMALIZER, normalizer);
325 }
326
327 if (!grn_proc_table_set_token_filters(ctx, table, token_filters_name)) {
328 grn_obj_remove(ctx, table);
329 goto exit;
330 }
331
332 grn_obj_unlink(ctx, table);
333 }
334
335exit :
336 grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
337 return NULL;
338}
339
340void
341grn_proc_init_table_create(grn_ctx *ctx)
342{
343 grn_expr_var vars[7];
344
345 grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
346 grn_plugin_expr_var_init(ctx, &(vars[1]), "flags", -1);
347 grn_plugin_expr_var_init(ctx, &(vars[2]), "key_type", -1);
348 grn_plugin_expr_var_init(ctx, &(vars[3]), "value_type", -1);
349 grn_plugin_expr_var_init(ctx, &(vars[4]), "default_tokenizer", -1);
350 grn_plugin_expr_var_init(ctx, &(vars[5]), "normalizer", -1);
351 grn_plugin_expr_var_init(ctx, &(vars[6]), "token_filters", -1);
352 grn_plugin_command_create(ctx,
353 "table_create", -1,
354 command_table_create,
355 7,
356 vars);
357}
358
359static int
360output_table_info(grn_ctx *ctx, grn_obj *table)
361{
362 grn_id id;
363 grn_obj o;
364 const char *path;
365 grn_table_flags flags;
366 grn_obj *default_tokenizer;
367 grn_obj *normalizer;
368 grn_obj *token_filters;
369
370 id = grn_obj_id(ctx, table);
371 path = grn_obj_path(ctx, table);
372 GRN_TEXT_INIT(&o, 0);
373 grn_ctx_output_array_open(ctx, "TABLE", 8);
374 grn_ctx_output_int64(ctx, id);
375 grn_proc_output_object_id_name(ctx, id);
376 grn_ctx_output_cstr(ctx, path);
377 GRN_BULK_REWIND(&o);
378
379 grn_table_get_info(ctx, table,
380 &flags,
381 NULL,
382 &default_tokenizer,
383 &normalizer,
384 &token_filters);
385 grn_dump_table_create_flags(ctx, flags, &o);
386 grn_ctx_output_obj(ctx, &o, NULL);
387 grn_proc_output_object_id_name(ctx, table->header.domain);
388 grn_proc_output_object_id_name(ctx, grn_obj_get_range(ctx, table));
389 grn_proc_output_object_name(ctx, default_tokenizer);
390 grn_proc_output_object_name(ctx, normalizer);
391 grn_ctx_output_array_close(ctx);
392 GRN_OBJ_FIN(ctx, &o);
393 return 1;
394}
395
396static grn_obj *
397command_table_list(grn_ctx *ctx, int nargs, grn_obj **args,
398 grn_user_data *user_data)
399{
400 grn_obj *db;
401 grn_obj tables;
402 int n_top_level_elements;
403 int n_elements_for_header = 1;
404 int n_tables;
405 int i;
406
407 db = grn_ctx_db(ctx);
408
409 {
410 grn_table_cursor *cursor;
411 grn_id id;
412 grn_obj *prefix;
413 const void *min = NULL;
414 unsigned int min_size = 0;
415 int flags = 0;
416
417 prefix = grn_plugin_proc_get_var(ctx, user_data, "prefix", -1);
418 if (GRN_TEXT_LEN(prefix) > 0) {
419 min = GRN_TEXT_VALUE(prefix);
420 min_size = GRN_TEXT_LEN(prefix);
421 flags |= GRN_CURSOR_PREFIX;
422 }
423 cursor = grn_table_cursor_open(ctx, db,
424 min, min_size,
425 NULL, 0,
426 0, -1, flags);
427 if (!cursor) {
428 return NULL;
429 }
430
431 GRN_PTR_INIT(&tables, GRN_OBJ_VECTOR, GRN_ID_NIL);
432 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
433 grn_obj *object;
434 const char *name;
435 void *key;
436 int i, key_size;
437 grn_bool have_period = GRN_FALSE;
438
439 key_size = grn_table_cursor_get_key(ctx, cursor, &key);
440 name = key;
441 for (i = 0; i < key_size; i++) {
442 if (name[i] == '.') {
443 have_period = GRN_TRUE;
444 break;
445 }
446 }
447 if (have_period) {
448 continue;
449 }
450
451 object = grn_ctx_at(ctx, id);
452 if (object) {
453 if (grn_obj_is_table(ctx, object)) {
454 GRN_PTR_PUT(ctx, &tables, object);
455 } else {
456 grn_obj_unlink(ctx, object);
457 }
458 } else {
459 if (ctx->rc != GRN_SUCCESS) {
460 ERRCLR(ctx);
461 }
462 }
463 }
464 grn_table_cursor_close(ctx, cursor);
465 }
466 n_tables = GRN_BULK_VSIZE(&tables) / sizeof(grn_obj *);
467 n_top_level_elements = n_elements_for_header + n_tables;
468 grn_ctx_output_array_open(ctx, "TABLE_LIST", n_top_level_elements);
469
470 grn_ctx_output_array_open(ctx, "HEADER", 8);
471 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
472 grn_ctx_output_cstr(ctx, "id");
473 grn_ctx_output_cstr(ctx, "UInt32");
474 grn_ctx_output_array_close(ctx);
475 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
476 grn_ctx_output_cstr(ctx, "name");
477 grn_ctx_output_cstr(ctx, "ShortText");
478 grn_ctx_output_array_close(ctx);
479 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
480 grn_ctx_output_cstr(ctx, "path");
481 grn_ctx_output_cstr(ctx, "ShortText");
482 grn_ctx_output_array_close(ctx);
483 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
484 grn_ctx_output_cstr(ctx, "flags");
485 grn_ctx_output_cstr(ctx, "ShortText");
486 grn_ctx_output_array_close(ctx);
487 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
488 grn_ctx_output_cstr(ctx, "domain");
489 grn_ctx_output_cstr(ctx, "ShortText");
490 grn_ctx_output_array_close(ctx);
491 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
492 grn_ctx_output_cstr(ctx, "range");
493 grn_ctx_output_cstr(ctx, "ShortText");
494 grn_ctx_output_array_close(ctx);
495 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
496 grn_ctx_output_cstr(ctx, "default_tokenizer");
497 grn_ctx_output_cstr(ctx, "ShortText");
498 grn_ctx_output_array_close(ctx);
499 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
500 grn_ctx_output_cstr(ctx, "normalizer");
501 grn_ctx_output_cstr(ctx, "ShortText");
502 grn_ctx_output_array_close(ctx);
503 grn_ctx_output_array_close(ctx);
504
505 for (i = 0; i < n_tables; i++) {
506 grn_obj *table = GRN_PTR_VALUE_AT(&tables, i);
507 output_table_info(ctx, table);
508 grn_obj_unlink(ctx, table);
509 }
510 GRN_OBJ_FIN(ctx, &tables);
511
512 grn_ctx_output_array_close(ctx);
513
514 return NULL;
515}
516
517void
518grn_proc_init_table_list(grn_ctx *ctx)
519{
520 grn_expr_var vars[1];
521
522 grn_plugin_expr_var_init(ctx, &(vars[0]), "prefix", -1);
523 grn_plugin_command_create(ctx,
524 "table_list", -1,
525 command_table_list,
526 1,
527 vars);
528}
529
530static grn_obj *
531command_table_remove(grn_ctx *ctx,
532 int nargs,
533 grn_obj **args,
534 grn_user_data *user_data)
535{
536 grn_obj *name;
537 grn_obj *table;
538 grn_bool dependent;
539
540 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
541 dependent = grn_plugin_proc_get_var_bool(ctx, user_data, "dependent", -1,
542 GRN_FALSE);
543 table = grn_ctx_get(ctx,
544 GRN_TEXT_VALUE(name),
545 GRN_TEXT_LEN(name));
546 if (!table) {
547 GRN_PLUGIN_ERROR(ctx,
548 GRN_INVALID_ARGUMENT,
549 "[table][remove] table isn't found: <%.*s>",
550 (int)GRN_TEXT_LEN(name),
551 GRN_TEXT_VALUE(name));
552 grn_ctx_output_bool(ctx, GRN_FALSE);
553 return NULL;
554 }
555
556 if (!grn_obj_is_table(ctx, table)) {
557 const char *type_name;
558 type_name = grn_obj_type_to_string(table->header.type);
559 grn_obj_unlink(ctx, table);
560 GRN_PLUGIN_ERROR(ctx,
561 GRN_INVALID_ARGUMENT,
562 "[table][remove] not table: <%.*s>: <%s>",
563 (int)GRN_TEXT_LEN(name),
564 GRN_TEXT_VALUE(name),
565 type_name);
566 grn_ctx_output_bool(ctx, GRN_FALSE);
567 return NULL;
568 }
569
570 if (dependent) {
571 grn_obj_remove_dependent(ctx, table);
572 } else {
573 grn_obj_remove(ctx, table);
574 }
575 grn_ctx_output_bool(ctx, !ctx->rc);
576 return NULL;
577}
578
579void
580grn_proc_init_table_remove(grn_ctx *ctx)
581{
582 grn_expr_var vars[2];
583
584 grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
585 grn_plugin_expr_var_init(ctx, &(vars[1]), "dependent", -1);
586 grn_plugin_command_create(ctx,
587 "table_remove", -1,
588 command_table_remove,
589 2,
590 vars);
591}
592
593static grn_obj *
594command_table_rename(grn_ctx *ctx,
595 int nargs,
596 grn_obj **args,
597 grn_user_data *user_data)
598{
599 grn_rc rc = GRN_SUCCESS;
600 grn_obj *name;
601 grn_obj *new_name;
602 grn_obj *table = NULL;
603
604 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
605 new_name = grn_plugin_proc_get_var(ctx, user_data, "new_name", -1);
606 if (GRN_TEXT_LEN(name) == 0) {
607 rc = GRN_INVALID_ARGUMENT;
608 GRN_PLUGIN_ERROR(ctx, rc, "[table][rename] table name isn't specified");
609 goto exit;
610 }
611 table = grn_ctx_get(ctx, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name));
612 if (!table) {
613 rc = GRN_INVALID_ARGUMENT;
614 GRN_PLUGIN_ERROR(ctx,
615 rc,
616 "[table][rename] table isn't found: <%.*s>",
617 (int)GRN_TEXT_LEN(name),
618 GRN_TEXT_VALUE(name));
619 goto exit;
620 }
621 if (GRN_TEXT_LEN(new_name) == 0) {
622 rc = GRN_INVALID_ARGUMENT;
623 GRN_PLUGIN_ERROR(ctx,
624 rc,
625 "[table][rename] new table name isn't specified: <%.*s>",
626 (int)GRN_TEXT_LEN(name),
627 GRN_TEXT_VALUE(name));
628 goto exit;
629 }
630 rc = grn_table_rename(ctx, table,
631 GRN_TEXT_VALUE(new_name),
632 GRN_TEXT_LEN(new_name));
633 if (rc != GRN_SUCCESS && ctx->rc == GRN_SUCCESS) {
634 GRN_PLUGIN_ERROR(ctx,
635 rc,
636 "[table][rename] failed to rename: <%.*s> -> <%.*s>",
637 (int)GRN_TEXT_LEN(name),
638 GRN_TEXT_VALUE(name),
639 (int)GRN_TEXT_LEN(new_name),
640 GRN_TEXT_VALUE(new_name));
641 }
642exit :
643 grn_ctx_output_bool(ctx, !rc);
644 if (table) { grn_obj_unlink(ctx, table); }
645 return NULL;
646}
647
648void
649grn_proc_init_table_rename(grn_ctx *ctx)
650{
651 grn_expr_var vars[2];
652
653 grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
654 grn_plugin_expr_var_init(ctx, &(vars[1]), "new_name", -1);
655 grn_plugin_command_create(ctx,
656 "table_rename", -1,
657 command_table_rename,
658 2,
659 vars);
660}
661
662static grn_rc
663command_table_copy_resolve_target(grn_ctx *ctx,
664 const char *label,
665 grn_obj *name,
666 grn_obj **table)
667{
668 if (GRN_TEXT_LEN(name) == 0) {
669 GRN_PLUGIN_ERROR(ctx,
670 GRN_INVALID_ARGUMENT,
671 "[table][copy] %s name isn't specified",
672 label);
673 return ctx->rc;
674 }
675 *table = grn_ctx_get(ctx,
676 GRN_TEXT_VALUE(name),
677 GRN_TEXT_LEN(name));
678 if (!*table) {
679 GRN_PLUGIN_ERROR(ctx,
680 GRN_INVALID_ARGUMENT,
681 "[table][copy] %s table isn't found: <%.*s>",
682 label,
683 (int)GRN_TEXT_LEN(name),
684 GRN_TEXT_VALUE(name));
685 return ctx->rc;
686 }
687
688 return ctx->rc;
689}
690
691static void
692command_table_copy_same_key_type(grn_ctx *ctx,
693 grn_obj *from_table,
694 grn_obj *to_table,
695 grn_obj *from_name,
696 grn_obj *to_name)
697{
698 GRN_TABLE_EACH_BEGIN_FLAGS(ctx, from_table, cursor, from_id,
699 GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING) {
700 void *key;
701 int key_size;
702 grn_id to_id;
703
704 key_size = grn_table_cursor_get_key(ctx, cursor, &key);
705 to_id = grn_table_add(ctx, to_table, key, key_size, NULL);
706 if (to_id == GRN_ID_NIL) {
707 grn_obj key_buffer;
708 grn_obj inspected_key;
709 if (from_table->header.domain == GRN_DB_SHORT_TEXT) {
710 GRN_SHORT_TEXT_INIT(&key_buffer, 0);
711 } else {
712 GRN_VALUE_FIX_SIZE_INIT(&key_buffer, 0, from_table->header.domain);
713 }
714 grn_bulk_write(ctx, &key_buffer, key, key_size);
715 GRN_TEXT_INIT(&inspected_key, 0);
716 grn_inspect(ctx, &inspected_key, &key_buffer);
717 GRN_PLUGIN_ERROR(ctx,
718 GRN_INVALID_ARGUMENT,
719 "[table][copy] failed to copy key: <%.*s>: "
720 "<%.*s> -> <%.*s>",
721 (int)GRN_TEXT_LEN(&inspected_key),
722 GRN_TEXT_VALUE(&inspected_key),
723 (int)GRN_TEXT_LEN(from_name),
724 GRN_TEXT_VALUE(from_name),
725 (int)GRN_TEXT_LEN(to_name),
726 GRN_TEXT_VALUE(to_name));
727 GRN_OBJ_FIN(ctx, &inspected_key);
728 GRN_OBJ_FIN(ctx, &key_buffer);
729 break;
730 }
731 } GRN_TABLE_EACH_END(ctx, cursor);
732}
733
734static void
735command_table_copy_different(grn_ctx *ctx,
736 grn_obj *from_table,
737 grn_obj *to_table,
738 grn_obj *from_name,
739 grn_obj *to_name)
740{
741 grn_obj from_key_buffer;
742 grn_obj to_key_buffer;
743
744 if (from_table->header.domain == GRN_DB_SHORT_TEXT) {
745 GRN_SHORT_TEXT_INIT(&from_key_buffer, 0);
746 } else {
747 GRN_VALUE_FIX_SIZE_INIT(&from_key_buffer, 0, from_table->header.domain);
748 }
749 if (to_table->header.domain == GRN_DB_SHORT_TEXT) {
750 GRN_SHORT_TEXT_INIT(&to_key_buffer, 0);
751 } else {
752 GRN_VALUE_FIX_SIZE_INIT(&to_key_buffer, 0, to_table->header.domain);
753 }
754
755 GRN_TABLE_EACH_BEGIN_FLAGS(ctx, from_table, cursor, from_id,
756 GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING) {
757 void *key;
758 int key_size;
759 grn_rc cast_rc;
760 grn_id to_id;
761
762 GRN_BULK_REWIND(&from_key_buffer);
763 GRN_BULK_REWIND(&to_key_buffer);
764
765 key_size = grn_table_cursor_get_key(ctx, cursor, &key);
766 grn_bulk_write(ctx, &from_key_buffer, key, key_size);
767 cast_rc = grn_obj_cast(ctx, &from_key_buffer, &to_key_buffer, GRN_FALSE);
768 if (cast_rc != GRN_SUCCESS) {
769 grn_obj *to_key_type;
770 grn_obj inspected_key;
771 grn_obj inspected_to_key_type;
772
773 to_key_type = grn_ctx_at(ctx, to_table->header.domain);
774 GRN_TEXT_INIT(&inspected_key, 0);
775 GRN_TEXT_INIT(&inspected_to_key_type, 0);
776 grn_inspect(ctx, &inspected_key, &from_key_buffer);
777 grn_inspect(ctx, &inspected_to_key_type, to_key_type);
778 ERR(cast_rc,
779 "[table][copy] failed to cast key: <%.*s> -> %.*s: "
780 "<%.*s> -> <%.*s>",
781 (int)GRN_TEXT_LEN(&inspected_key),
782 GRN_TEXT_VALUE(&inspected_key),
783 (int)GRN_TEXT_LEN(&inspected_to_key_type),
784 GRN_TEXT_VALUE(&inspected_to_key_type),
785 (int)GRN_TEXT_LEN(from_name),
786 GRN_TEXT_VALUE(from_name),
787 (int)GRN_TEXT_LEN(to_name),
788 GRN_TEXT_VALUE(to_name));
789 GRN_OBJ_FIN(ctx, &inspected_key);
790 GRN_OBJ_FIN(ctx, &inspected_to_key_type);
791 break;
792 }
793
794 to_id = grn_table_add(ctx, to_table,
795 GRN_BULK_HEAD(&to_key_buffer),
796 GRN_BULK_VSIZE(&to_key_buffer),
797 NULL);
798 if (to_id == GRN_ID_NIL) {
799 grn_obj inspected_from_key;
800 grn_obj inspected_to_key;
801 GRN_TEXT_INIT(&inspected_from_key, 0);
802 GRN_TEXT_INIT(&inspected_to_key, 0);
803 grn_inspect(ctx, &inspected_from_key, &from_key_buffer);
804 grn_inspect(ctx, &inspected_to_key, &to_key_buffer);
805 GRN_PLUGIN_ERROR(ctx,
806 GRN_INVALID_ARGUMENT,
807 "[table][copy] failed to copy key: <%.*s> -> <%.*s>: "
808 "<%.*s> -> <%.*s>",
809 (int)GRN_TEXT_LEN(&inspected_from_key),
810 GRN_TEXT_VALUE(&inspected_from_key),
811 (int)GRN_TEXT_LEN(&inspected_to_key),
812 GRN_TEXT_VALUE(&inspected_to_key),
813 (int)GRN_TEXT_LEN(from_name),
814 GRN_TEXT_VALUE(from_name),
815 (int)GRN_TEXT_LEN(to_name),
816 GRN_TEXT_VALUE(to_name));
817 GRN_OBJ_FIN(ctx, &inspected_from_key);
818 GRN_OBJ_FIN(ctx, &inspected_to_key);
819 break;
820 }
821 } GRN_TABLE_EACH_END(ctx, cursor);
822 GRN_OBJ_FIN(ctx, &from_key_buffer);
823 GRN_OBJ_FIN(ctx, &to_key_buffer);
824}
825
826static grn_obj *
827command_table_copy(grn_ctx *ctx,
828 int nargs,
829 grn_obj **args,
830 grn_user_data *user_data)
831{
832 grn_rc rc = GRN_SUCCESS;
833 grn_obj *from_table = NULL;
834 grn_obj *to_table = NULL;
835 grn_obj *from_name;
836 grn_obj *to_name;
837
838 from_name = grn_plugin_proc_get_var(ctx, user_data, "from_name", -1);
839 to_name = grn_plugin_proc_get_var(ctx, user_data, "to_name", -1);
840
841 rc = command_table_copy_resolve_target(ctx, "from", from_name, &from_table);
842 if (rc != GRN_SUCCESS) {
843 goto exit;
844 }
845 rc = command_table_copy_resolve_target(ctx, "to", to_name, &to_table);
846 if (rc != GRN_SUCCESS) {
847 goto exit;
848 }
849
850 if (from_table->header.type == GRN_TABLE_NO_KEY ||
851 to_table->header.type == GRN_TABLE_NO_KEY) {
852 GRN_PLUGIN_ERROR(ctx,
853 GRN_OPERATION_NOT_SUPPORTED,
854 "[table][copy] copy from/to TABLE_NO_KEY isn't supported: "
855 "<%.*s> -> <%.*s>",
856 (int)GRN_TEXT_LEN(from_name),
857 GRN_TEXT_VALUE(from_name),
858 (int)GRN_TEXT_LEN(to_name),
859 GRN_TEXT_VALUE(to_name));
860 rc = ctx->rc;
861 goto exit;
862 }
863
864 if (from_table == to_table) {
865 GRN_PLUGIN_ERROR(ctx,
866 GRN_OPERATION_NOT_SUPPORTED,
867 "[table][copy] from table and to table is the same: "
868 "<%.*s>",
869 (int)GRN_TEXT_LEN(from_name),
870 GRN_TEXT_VALUE(from_name));
871 rc = ctx->rc;
872 goto exit;
873 }
874
875 if (from_table->header.domain == to_table->header.domain) {
876 command_table_copy_same_key_type(ctx,
877 from_table, to_table,
878 from_name, to_name);
879 } else {
880 command_table_copy_different(ctx,
881 from_table, to_table,
882 from_name, to_name);
883 }
884
885exit :
886 grn_ctx_output_bool(ctx, rc == GRN_SUCCESS);
887
888 if (to_table) {
889 grn_obj_unlink(ctx, to_table);
890 }
891 if (from_table) {
892 grn_obj_unlink(ctx, from_table);
893 }
894
895 return NULL;
896}
897
898void
899grn_proc_init_table_copy(grn_ctx *ctx)
900{
901 grn_expr_var vars[2];
902
903 grn_plugin_expr_var_init(ctx, &(vars[0]), "from_name", -1);
904 grn_plugin_expr_var_init(ctx, &(vars[1]), "to_name", -1);
905 grn_plugin_command_create(ctx,
906 "table_copy", -1,
907 command_table_copy,
908 2,
909 vars);
910}
911