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_db.h"
23#include "../grn_str.h"
24
25#include <groonga/plugin.h>
26
27grn_column_flags
28grn_proc_column_parse_flags(grn_ctx *ctx,
29 const char *error_message_tag,
30 const char *text,
31 const char *end)
32{
33 grn_column_flags flags = 0;
34 while (text < end) {
35 size_t name_size;
36
37 if (*text == '|' || *text == ' ') {
38 text += 1;
39 continue;
40 }
41
42#define CHECK_FLAG(name) \
43 name_size = strlen(#name); \
44 if ((end - text) >= name_size && \
45 memcmp(text, #name, name_size) == 0) { \
46 flags |= GRN_OBJ_ ## name; \
47 text += name_size; \
48 continue; \
49 }
50
51 CHECK_FLAG(COLUMN_SCALAR);
52 CHECK_FLAG(COLUMN_VECTOR);
53 CHECK_FLAG(COLUMN_INDEX);
54 CHECK_FLAG(COMPRESS_ZLIB);
55 CHECK_FLAG(COMPRESS_LZ4);
56 CHECK_FLAG(COMPRESS_ZSTD);
57 CHECK_FLAG(WITH_SECTION);
58 CHECK_FLAG(WITH_WEIGHT);
59 CHECK_FLAG(WITH_POSITION);
60 CHECK_FLAG(RING_BUFFER);
61 CHECK_FLAG(INDEX_SMALL);
62 CHECK_FLAG(INDEX_MEDIUM);
63
64#undef CHECK_FLAG
65
66 ERR(GRN_INVALID_ARGUMENT,
67 "%s unknown flag: <%.*s>",
68 error_message_tag,
69 (int)(end - text), text);
70 return 0;
71 }
72 return flags;
73}
74
75static grn_rc
76command_column_create_resolve_source_name(grn_ctx *ctx,
77 grn_obj *table,
78 const char *source_name,
79 int source_name_length,
80 grn_obj *source_ids)
81{
82 grn_obj *column;
83
84 column = grn_obj_column(ctx, table, source_name, source_name_length);
85 if (!column) {
86 ERR(GRN_INVALID_ARGUMENT,
87 "[column][create] nonexistent source: <%.*s>",
88 source_name_length, source_name);
89 return ctx->rc;
90 }
91
92 if (column->header.type == GRN_ACCESSOR) {
93 if (strncmp(source_name, "_key", source_name_length) == 0) {
94 grn_id source_id = grn_obj_id(ctx, table);
95 GRN_UINT32_PUT(ctx, source_ids, source_id);
96 } else {
97 ERR(GRN_INVALID_ARGUMENT,
98 "[column][create] pseudo column except <_key> is invalid: <%.*s>",
99 source_name_length, source_name);
100 }
101 } else {
102 grn_id source_id = grn_obj_id(ctx, column);
103 GRN_UINT32_PUT(ctx, source_ids, source_id);
104 }
105 grn_obj_unlink(ctx, column);
106
107 return ctx->rc;
108}
109
110static grn_rc
111command_column_create_resolve_source_names(grn_ctx *ctx,
112 grn_obj *table,
113 grn_obj *source_names,
114 grn_obj *source_ids)
115{
116 int i, names_length;
117 int start, source_name_length;
118 const char *names;
119
120 names = GRN_TEXT_VALUE(source_names);
121 start = 0;
122 source_name_length = 0;
123 names_length = GRN_TEXT_LEN(source_names);
124 for (i = 0; i < names_length; i++) {
125 switch (names[i]) {
126 case ' ' :
127 if (source_name_length == 0) {
128 start++;
129 }
130 break;
131 case ',' :
132 {
133 grn_rc rc;
134 const char *source_name = names + start;
135 rc = command_column_create_resolve_source_name(ctx,
136 table,
137 source_name,
138 source_name_length,
139 source_ids);
140 if (rc) {
141 return rc;
142 }
143 start = i + 1;
144 source_name_length = 0;
145 }
146 break;
147 default :
148 source_name_length++;
149 break;
150 }
151 }
152
153 if (source_name_length > 0) {
154 grn_rc rc;
155 const char *source_name = names + start;
156 rc = command_column_create_resolve_source_name(ctx,
157 table,
158 source_name,
159 source_name_length,
160 source_ids);
161 if (rc) {
162 return rc;
163 }
164 }
165
166 return GRN_SUCCESS;
167}
168
169static grn_obj *
170command_column_create(grn_ctx *ctx, int nargs, grn_obj **args,
171 grn_user_data *user_data)
172{
173 grn_bool succeeded = GRN_TRUE;
174 grn_obj *table;
175 grn_obj *column;
176 grn_obj *table_raw;
177 grn_obj *name;
178 grn_obj *flags_raw;
179 grn_obj *type_raw;
180 grn_obj *source_raw;
181 grn_column_flags flags;
182 grn_obj *type = NULL;
183
184 table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
185 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
186 flags_raw = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
187 type_raw = grn_plugin_proc_get_var(ctx, user_data, "type", -1);
188 source_raw = grn_plugin_proc_get_var(ctx, user_data, "source", -1);
189
190 table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_raw), GRN_TEXT_LEN(table_raw));
191 if (!table) {
192 GRN_PLUGIN_ERROR(ctx,
193 GRN_INVALID_ARGUMENT,
194 "[column][create] table doesn't exist: <%.*s>",
195 (int)GRN_TEXT_LEN(table_raw),
196 GRN_TEXT_VALUE(table_raw));
197 succeeded = GRN_FALSE;
198 goto exit;
199 }
200
201 {
202 const char *rest;
203 flags = grn_atoi(GRN_TEXT_VALUE(flags_raw),
204 GRN_BULK_CURR(flags_raw),
205 &rest);
206 if (GRN_TEXT_VALUE(flags_raw) == rest) {
207 flags = grn_proc_column_parse_flags(ctx,
208 "[column][create][flags]",
209 GRN_TEXT_VALUE(flags_raw),
210 GRN_BULK_CURR(flags_raw));
211 if (ctx->rc) {
212 succeeded = GRN_FALSE;
213 goto exit;
214 }
215 }
216 }
217
218 type = grn_ctx_get(ctx,
219 GRN_TEXT_VALUE(type_raw),
220 GRN_TEXT_LEN(type_raw));
221 if (!type) {
222 GRN_PLUGIN_ERROR(ctx,
223 GRN_INVALID_ARGUMENT,
224 "[column][create] type doesn't exist: <%.*s>",
225 (int)GRN_TEXT_LEN(type_raw),
226 GRN_TEXT_VALUE(type_raw));
227 succeeded = GRN_FALSE;
228 goto exit;
229 }
230
231 if (GRN_TEXT_LEN(name) == 0) {
232 GRN_PLUGIN_ERROR(ctx,
233 GRN_INVALID_ARGUMENT,
234 "[column][create] name is missing");
235 succeeded = GRN_FALSE;
236 goto exit;
237 }
238 flags |= GRN_OBJ_PERSISTENT;
239
240 column = grn_column_create(ctx, table,
241 GRN_TEXT_VALUE(name),
242 GRN_TEXT_LEN(name),
243 NULL, flags, type);
244 if (!column) {
245 succeeded = GRN_FALSE;
246 goto exit;
247 }
248
249 if (GRN_TEXT_LEN(source_raw) > 0) {
250 grn_rc rc;
251 grn_obj source_ids;
252 GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
253 rc = command_column_create_resolve_source_names(ctx,
254 type,
255 source_raw,
256 &source_ids);
257 if (rc == GRN_SUCCESS && GRN_BULK_VSIZE(&source_ids) > 0) {
258 grn_obj_set_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
259 rc = ctx->rc;
260 }
261 GRN_OBJ_FIN(ctx, &source_ids);
262 if (rc != GRN_SUCCESS) {
263 grn_obj_remove(ctx, column);
264 succeeded = GRN_FALSE;
265 goto exit;
266 }
267 }
268
269 grn_obj_unlink(ctx, column);
270
271exit :
272 grn_ctx_output_bool(ctx, succeeded);
273 if (table) { grn_obj_unlink(ctx, table); }
274 if (type) { grn_obj_unlink(ctx, type); }
275
276 return NULL;
277}
278
279void
280grn_proc_init_column_create(grn_ctx *ctx)
281{
282 grn_expr_var vars[5];
283
284 grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
285 grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1);
286 grn_plugin_expr_var_init(ctx, &(vars[2]), "flags", -1);
287 grn_plugin_expr_var_init(ctx, &(vars[3]), "type", -1);
288 grn_plugin_expr_var_init(ctx, &(vars[4]), "source", -1);
289 grn_plugin_command_create(ctx,
290 "column_create", -1,
291 command_column_create,
292 5,
293 vars);
294}
295
296static grn_obj *
297command_column_remove(grn_ctx *ctx, int nargs, grn_obj **args,
298 grn_user_data *user_data)
299{
300 grn_obj *table_raw;
301 grn_obj *name;
302 grn_obj *table;
303 grn_obj *column;
304 char fullname[GRN_TABLE_MAX_KEY_SIZE];
305 unsigned int fullname_len;
306
307 table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
308 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
309
310 table = grn_ctx_get(ctx,
311 GRN_TEXT_VALUE(table_raw),
312 GRN_TEXT_LEN(table_raw));
313
314 fullname_len = grn_obj_name(ctx, table, fullname, GRN_TABLE_MAX_KEY_SIZE);
315 if (fullname_len == 0) {
316 GRN_PLUGIN_ERROR(ctx,
317 GRN_INVALID_ARGUMENT,
318 "[column][remove] table isn't found: <%.*s>",
319 (int)GRN_TEXT_LEN(table_raw),
320 GRN_TEXT_VALUE(table_raw));
321 grn_ctx_output_bool(ctx, GRN_FALSE);
322 return NULL;
323 }
324
325 fullname[fullname_len] = GRN_DB_DELIMITER;
326 fullname_len++;
327 if (fullname_len + GRN_TEXT_LEN(name) > GRN_TABLE_MAX_KEY_SIZE) {
328 GRN_PLUGIN_ERROR(ctx,
329 GRN_INVALID_ARGUMENT,
330 "[column][remove] column name is too long: <%d> > <%u>: "
331 "<%.*s>",
332 (int)GRN_TEXT_LEN(name),
333 GRN_TABLE_MAX_KEY_SIZE - fullname_len,
334 (int)GRN_TEXT_LEN(name),
335 GRN_TEXT_VALUE(name));
336 grn_ctx_output_bool(ctx, GRN_FALSE);
337 return NULL;
338 }
339 grn_memcpy(fullname + fullname_len,
340 GRN_TEXT_VALUE(name),
341 GRN_TEXT_LEN(name));
342 fullname_len += GRN_TEXT_LEN(name);
343 column = grn_ctx_get(ctx, fullname, fullname_len);
344 if (!column) {
345 GRN_PLUGIN_ERROR(ctx,
346 GRN_INVALID_ARGUMENT,
347 "[column][remove] column isn't found: <%.*s%c%.*s>",
348 (int)GRN_TEXT_LEN(table_raw),
349 GRN_TEXT_VALUE(table_raw),
350 GRN_DB_DELIMITER,
351 (int)GRN_TEXT_LEN(name),
352 GRN_TEXT_VALUE(name));
353 grn_ctx_output_bool(ctx, GRN_FALSE);
354 return NULL;
355 }
356
357 grn_obj_remove(ctx, column);
358 grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
359 return NULL;
360}
361
362void
363grn_proc_init_column_remove(grn_ctx *ctx)
364{
365 grn_expr_var vars[2];
366
367 grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
368 grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1);
369 grn_plugin_command_create(ctx,
370 "column_remove", -1,
371 command_column_remove,
372 2,
373 vars);
374}
375
376static grn_obj *
377command_column_rename(grn_ctx *ctx, int nargs, grn_obj **args,
378 grn_user_data *user_data)
379{
380 grn_rc rc = GRN_SUCCESS;
381 grn_obj *table_raw;
382 grn_obj *name;
383 grn_obj *new_name;
384 grn_obj *table = NULL;
385 grn_obj *column = NULL;
386
387 table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
388 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
389 new_name = grn_plugin_proc_get_var(ctx, user_data, "new_name", -1);
390
391 if (GRN_TEXT_LEN(table_raw) == 0) {
392 rc = GRN_INVALID_ARGUMENT;
393 GRN_PLUGIN_ERROR(ctx,
394 rc,
395 "[column][rename] table name isn't specified");
396 goto exit;
397 }
398
399 table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_raw), GRN_TEXT_LEN(table_raw));
400 if (!table) {
401 rc = GRN_INVALID_ARGUMENT;
402 GRN_PLUGIN_ERROR(ctx,
403 rc,
404 "[column][rename] table isn't found: <%.*s>",
405 (int)GRN_TEXT_LEN(table_raw),
406 GRN_TEXT_VALUE(table_raw));
407 goto exit;
408 }
409
410 if (GRN_TEXT_LEN(name) == 0) {
411 rc = GRN_INVALID_ARGUMENT;
412 GRN_PLUGIN_ERROR(ctx,
413 rc,
414 "[column][rename] column name isn't specified: <%.*s>",
415 (int)GRN_TEXT_LEN(table_raw),
416 GRN_TEXT_VALUE(table_raw));
417 goto exit;
418 }
419
420 column = grn_obj_column(ctx, table,
421 GRN_TEXT_VALUE(name),
422 GRN_TEXT_LEN(name));
423 if (!column) {
424 rc = GRN_INVALID_ARGUMENT;
425 GRN_PLUGIN_ERROR(ctx,
426 rc,
427 "[column][rename] column isn't found: <%.*s%c%.*s>",
428 (int)GRN_TEXT_LEN(table_raw),
429 GRN_TEXT_VALUE(table_raw),
430 GRN_DB_DELIMITER,
431 (int)GRN_TEXT_LEN(name),
432 GRN_TEXT_VALUE(name));
433 goto exit;
434 }
435
436 if (GRN_TEXT_LEN(new_name) == 0) {
437 rc = GRN_INVALID_ARGUMENT;
438 GRN_PLUGIN_ERROR(ctx,
439 rc,
440 "[column][rename] new column name isn't specified: "
441 "<%.*s%c%.*s>",
442 (int)GRN_TEXT_LEN(table_raw),
443 GRN_TEXT_VALUE(table_raw),
444 GRN_DB_DELIMITER,
445 (int)GRN_TEXT_LEN(name),
446 GRN_TEXT_VALUE(name));
447 goto exit;
448 }
449
450 rc = grn_column_rename(ctx, column,
451 GRN_TEXT_VALUE(new_name),
452 GRN_TEXT_LEN(new_name));
453 if (rc != GRN_SUCCESS && ctx->rc == GRN_SUCCESS) {
454 GRN_PLUGIN_ERROR(ctx,
455 rc,
456 "[column][rename] failed to rename: "
457 "<%.*s%c%.*s> -> <%.*s%c%.*s>",
458 (int)GRN_TEXT_LEN(table_raw),
459 GRN_TEXT_VALUE(table_raw),
460 GRN_DB_DELIMITER,
461 (int)GRN_TEXT_LEN(name),
462 GRN_TEXT_VALUE(name),
463 (int)GRN_TEXT_LEN(table_raw),
464 GRN_TEXT_VALUE(table_raw),
465 GRN_DB_DELIMITER,
466 (int)GRN_TEXT_LEN(new_name),
467 GRN_TEXT_VALUE(new_name));
468 goto exit;
469 }
470
471exit :
472 grn_ctx_output_bool(ctx, rc == GRN_SUCCESS);
473 if (column) { grn_obj_unlink(ctx, column); }
474 if (table) { grn_obj_unlink(ctx, table); }
475 return NULL;
476}
477
478void
479grn_proc_init_column_rename(grn_ctx *ctx)
480{
481 grn_expr_var vars[3];
482
483 grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
484 grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1);
485 grn_plugin_expr_var_init(ctx, &(vars[2]), "new_name", -1);
486 grn_plugin_command_create(ctx,
487 "column_rename", -1,
488 command_column_rename,
489 3,
490 vars);
491}
492
493static void
494output_column_name(grn_ctx *ctx, grn_obj *column)
495{
496 grn_obj bulk;
497 int name_len;
498 char name[GRN_TABLE_MAX_KEY_SIZE];
499
500 GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY);
501 name_len = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
502 GRN_TEXT_SET(ctx, &bulk, name, name_len);
503
504 grn_ctx_output_obj(ctx, &bulk, NULL);
505 GRN_OBJ_FIN(ctx, &bulk);
506}
507
508static int
509output_column_info(grn_ctx *ctx, grn_obj *column)
510{
511 grn_obj o;
512 grn_id id;
513 const char *type;
514 const char *path;
515
516 switch (column->header.type) {
517 case GRN_COLUMN_FIX_SIZE:
518 type = "fix";
519 break;
520 case GRN_COLUMN_VAR_SIZE:
521 type = "var";
522 break;
523 case GRN_COLUMN_INDEX:
524 type = "index";
525 break;
526 default:
527 GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid header type %d\n", column->header.type);
528 return 0;
529 }
530 id = grn_obj_id(ctx, column);
531 path = grn_obj_path(ctx, column);
532 GRN_TEXT_INIT(&o, 0);
533 grn_ctx_output_array_open(ctx, "COLUMN", 8);
534 grn_ctx_output_int64(ctx, id);
535 output_column_name(ctx, column);
536 grn_ctx_output_cstr(ctx, path);
537 grn_ctx_output_cstr(ctx, type);
538 grn_dump_column_create_flags(ctx, grn_column_get_flags(ctx, column), &o);
539 grn_ctx_output_obj(ctx, &o, NULL);
540 grn_proc_output_object_id_name(ctx, column->header.domain);
541 grn_proc_output_object_id_name(ctx, grn_obj_get_range(ctx, column));
542 {
543 grn_db_obj *obj = (grn_db_obj *)column;
544 grn_id *s = obj->source;
545 int i = 0, n = obj->source_size / sizeof(grn_id);
546 grn_ctx_output_array_open(ctx, "SOURCES", n);
547 for (i = 0; i < n; i++, s++) {
548 grn_proc_output_object_id_name(ctx, *s);
549 }
550 grn_ctx_output_array_close(ctx);
551
552 }
553 /* output_obj_source(ctx, (grn_db_obj *)column); */
554 grn_ctx_output_array_close(ctx);
555 GRN_OBJ_FIN(ctx, &o);
556 return 1;
557}
558
559static grn_obj *
560command_column_list(grn_ctx *ctx, int nargs, grn_obj **args,
561 grn_user_data *user_data)
562{
563 grn_obj *table_raw;
564 grn_obj *table;
565 grn_hash *cols;
566 grn_obj *col;
567 int column_list_size = -1;
568
569 table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
570
571 table = grn_ctx_get(ctx,
572 GRN_TEXT_VALUE(table_raw),
573 GRN_TEXT_LEN(table_raw));
574 if (!table) {
575 GRN_PLUGIN_ERROR(ctx,
576 GRN_INVALID_ARGUMENT,
577 "[column][list] table doesn't exist: <%.*s>",
578 (int)GRN_TEXT_LEN(table_raw),
579 GRN_TEXT_VALUE(table_raw));
580 return NULL;
581 }
582
583 if (!grn_obj_is_table(ctx, table)) {
584 const char *type_name;
585 type_name = grn_obj_type_to_string(table->header.type);
586 grn_obj_unlink(ctx, table);
587 GRN_PLUGIN_ERROR(ctx,
588 GRN_INVALID_ARGUMENT,
589 "[column][list] not table: <%.*s>: <%s>",
590 (int)GRN_TEXT_LEN(table_raw),
591 GRN_TEXT_VALUE(table_raw),
592 type_name);
593 return NULL;
594 }
595
596 column_list_size = 1; /* [header, (key), (COLUMNS)] */
597 if (table->header.type != GRN_TABLE_NO_KEY) {
598 column_list_size++;
599 }
600 cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
601 GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
602 if (!cols) {
603 grn_obj_unlink(ctx, table);
604 GRN_PLUGIN_ERROR(ctx,
605 GRN_INVALID_ARGUMENT,
606 "[column][list] "
607 "failed to create temporary table to list columns: <%.*s>",
608 (int)GRN_TEXT_LEN(table_raw),
609 GRN_TEXT_VALUE(table_raw));
610 return NULL;
611 }
612
613 column_list_size += grn_table_columns(ctx, table, NULL, 0, (grn_obj *)cols);
614
615 grn_ctx_output_array_open(ctx, "COLUMN_LIST", column_list_size);
616 grn_ctx_output_array_open(ctx, "HEADER", 8);
617 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
618 grn_ctx_output_cstr(ctx, "id");
619 grn_ctx_output_cstr(ctx, "UInt32");
620 grn_ctx_output_array_close(ctx);
621 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
622 grn_ctx_output_cstr(ctx, "name");
623 grn_ctx_output_cstr(ctx, "ShortText");
624 grn_ctx_output_array_close(ctx);
625 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
626 grn_ctx_output_cstr(ctx, "path");
627 grn_ctx_output_cstr(ctx, "ShortText");
628 grn_ctx_output_array_close(ctx);
629 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
630 grn_ctx_output_cstr(ctx, "type");
631 grn_ctx_output_cstr(ctx, "ShortText");
632 grn_ctx_output_array_close(ctx);
633 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
634 grn_ctx_output_cstr(ctx, "flags");
635 grn_ctx_output_cstr(ctx, "ShortText");
636 grn_ctx_output_array_close(ctx);
637 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
638 grn_ctx_output_cstr(ctx, "domain");
639 grn_ctx_output_cstr(ctx, "ShortText");
640 grn_ctx_output_array_close(ctx);
641 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
642 grn_ctx_output_cstr(ctx, "range");
643 grn_ctx_output_cstr(ctx, "ShortText");
644 grn_ctx_output_array_close(ctx);
645 grn_ctx_output_array_open(ctx, "PROPERTY", 2);
646 grn_ctx_output_cstr(ctx, "source");
647 grn_ctx_output_cstr(ctx, "ShortText");
648 grn_ctx_output_array_close(ctx);
649 grn_ctx_output_array_close(ctx);
650
651 if ((col = grn_obj_column(ctx, table,
652 GRN_COLUMN_NAME_KEY,
653 GRN_COLUMN_NAME_KEY_LEN))) {
654 int name_len;
655 char name_buf[GRN_TABLE_MAX_KEY_SIZE];
656 grn_id id;
657 grn_obj buf;
658 GRN_TEXT_INIT(&buf, 0);
659 grn_ctx_output_array_open(ctx, "COLUMN", 8);
660 id = grn_obj_id(ctx, table);
661 grn_ctx_output_int64(ctx, id);
662 grn_ctx_output_cstr(ctx, GRN_COLUMN_NAME_KEY);
663 grn_ctx_output_cstr(ctx, "");
664 grn_ctx_output_cstr(ctx, "");
665 grn_dump_column_create_flags(ctx, 0, &buf);
666 grn_ctx_output_obj(ctx, &buf, NULL);
667 name_len = grn_obj_name(ctx, table, name_buf, GRN_TABLE_MAX_KEY_SIZE);
668 grn_ctx_output_str(ctx, name_buf, name_len);
669 grn_proc_output_object_id_name(ctx, table->header.domain);
670 grn_ctx_output_array_open(ctx, "SOURCES", 0);
671 grn_ctx_output_array_close(ctx);
672 grn_ctx_output_array_close(ctx);
673 GRN_OBJ_FIN(ctx, &buf);
674 grn_obj_unlink(ctx, col);
675 }
676 {
677 grn_id *key;
678 GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
679 if ((col = grn_ctx_at(ctx, *key))) {
680 output_column_info(ctx, col);
681 grn_obj_unlink(ctx, col);
682 }
683 });
684 }
685 grn_ctx_output_array_close(ctx);
686 grn_hash_close(ctx, cols);
687 grn_obj_unlink(ctx, table);
688
689 return NULL;
690}
691
692void
693grn_proc_init_column_list(grn_ctx *ctx)
694{
695 grn_expr_var vars[1];
696
697 grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
698 grn_plugin_command_create(ctx,
699 "column_list", -1,
700 command_column_list,
701 1,
702 vars);
703}
704
705static grn_rc
706command_column_copy_resolve_target(grn_ctx *ctx,
707 const char *label,
708 grn_obj *table_name,
709 grn_obj *column_name,
710 grn_obj **table,
711 grn_obj **column)
712{
713 if (GRN_TEXT_LEN(table_name) == 0) {
714 ERR(GRN_INVALID_ARGUMENT,
715 "[column][copy] %s table name isn't specified",
716 label);
717 return ctx->rc;
718 }
719 *table = grn_ctx_get(ctx,
720 GRN_TEXT_VALUE(table_name),
721 GRN_TEXT_LEN(table_name));
722 if (!*table) {
723 ERR(GRN_INVALID_ARGUMENT,
724 "[column][copy] %s table isn't found: <%.*s>",
725 label,
726 (int)GRN_TEXT_LEN(table_name),
727 GRN_TEXT_VALUE(table_name));
728 return ctx->rc;
729 }
730
731 if (GRN_TEXT_LEN(column_name) == 0) {
732 ERR(GRN_INVALID_ARGUMENT,
733 "[column][copy] %s column name isn't specified: <%.*s>",
734 label,
735 (int)GRN_TEXT_LEN(table_name),
736 GRN_TEXT_VALUE(table_name));
737 return ctx->rc;
738 }
739 *column = grn_obj_column(ctx, *table,
740 GRN_TEXT_VALUE(column_name),
741 GRN_TEXT_LEN(column_name));
742 if (!*column) {
743 ERR(GRN_INVALID_ARGUMENT,
744 "[column][copy] %s column isn't found: <%.*s.%.*s>",
745 label,
746 (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
747 (int)GRN_TEXT_LEN(column_name), GRN_TEXT_VALUE(column_name));
748 return ctx->rc;
749 }
750
751 return ctx->rc;
752}
753
754static void
755command_column_copy_same_table(grn_ctx *ctx, grn_obj *table,
756 grn_obj *from_column, grn_obj *to_column)
757{
758 grn_table_cursor *cursor;
759 grn_id id;
760 grn_obj value;
761
762 cursor = grn_table_cursor_open(ctx, table,
763 NULL, 0,
764 NULL, 0,
765 0, -1, 0);
766 if (!cursor) {
767 return;
768 }
769
770 GRN_VOID_INIT(&value);
771 while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
772 GRN_BULK_REWIND(&value);
773 grn_obj_get_value(ctx, from_column, id, &value);
774 grn_obj_set_value(ctx, to_column, id, &value, GRN_OBJ_SET);
775 }
776 GRN_OBJ_FIN(ctx, &value);
777 grn_table_cursor_close(ctx, cursor);
778}
779
780static void
781command_column_copy_same_key_type(grn_ctx *ctx,
782 grn_obj *from_table,
783 grn_obj *from_column,
784 grn_obj *to_table,
785 grn_obj *to_column)
786{
787 grn_table_cursor *cursor;
788 grn_id from_id;
789 grn_obj value;
790
791 cursor = grn_table_cursor_open(ctx, from_table,
792 NULL, 0,
793 NULL, 0,
794 0, -1, 0);
795 if (!cursor) {
796 return;
797 }
798
799 GRN_VOID_INIT(&value);
800 while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
801 void *key;
802 int key_size;
803 grn_id to_id;
804
805 key_size = grn_table_cursor_get_key(ctx, cursor, &key);
806 to_id = grn_table_add(ctx, to_table, key, key_size, NULL);
807 if (to_id == GRN_ID_NIL) {
808 continue;
809 }
810
811 GRN_BULK_REWIND(&value);
812 grn_obj_get_value(ctx, from_column, from_id, &value);
813 grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET);
814 }
815 GRN_OBJ_FIN(ctx, &value);
816 grn_table_cursor_close(ctx, cursor);
817}
818
819static void
820command_column_copy_different(grn_ctx *ctx,
821 grn_obj *from_table,
822 grn_obj *from_column,
823 grn_obj *to_table,
824 grn_obj *to_column,
825 grn_obj *from_table_name,
826 grn_obj *from_column_name,
827 grn_obj *to_table_name,
828 grn_obj *to_column_name)
829{
830 grn_table_cursor *cursor;
831 grn_id from_id;
832 grn_obj from_key_buffer;
833 grn_obj to_key_buffer;
834 grn_obj value;
835
836 cursor = grn_table_cursor_open(ctx, from_table,
837 NULL, 0,
838 NULL, 0,
839 0, -1, 0);
840 if (!cursor) {
841 return;
842 }
843
844 if (from_table->header.domain == GRN_DB_SHORT_TEXT) {
845 GRN_SHORT_TEXT_INIT(&from_key_buffer, 0);
846 } else {
847 GRN_VALUE_FIX_SIZE_INIT(&from_key_buffer, 0, from_table->header.domain);
848 }
849 if (to_table->header.domain == GRN_DB_SHORT_TEXT) {
850 GRN_SHORT_TEXT_INIT(&to_key_buffer, 0);
851 } else {
852 GRN_VALUE_FIX_SIZE_INIT(&to_key_buffer, 0, to_table->header.domain);
853 }
854 GRN_VOID_INIT(&value);
855 while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
856 void *key;
857 int key_size;
858 grn_rc cast_rc;
859 grn_id to_id;
860
861 GRN_BULK_REWIND(&from_key_buffer);
862 GRN_BULK_REWIND(&to_key_buffer);
863
864 key_size = grn_table_cursor_get_key(ctx, cursor, &key);
865 grn_bulk_write(ctx, &from_key_buffer, key, key_size);
866 cast_rc = grn_obj_cast(ctx, &from_key_buffer, &to_key_buffer, GRN_FALSE);
867 if (cast_rc != GRN_SUCCESS) {
868 grn_obj *to_key_type;
869 grn_obj inspected_key;
870 grn_obj inspected_to_key_type;
871
872 to_key_type = grn_ctx_at(ctx, to_table->header.domain);
873 GRN_TEXT_INIT(&inspected_key, 0);
874 GRN_TEXT_INIT(&inspected_to_key_type, 0);
875 grn_inspect(ctx, &inspected_key, &from_key_buffer);
876 grn_inspect(ctx, &inspected_to_key_type, to_key_type);
877 ERR(cast_rc,
878 "[column][copy] failed to cast key: <%.*s> -> %.*s: "
879 "<%.*s.%.*s> -> <%.*s.%.*s>",
880 (int)GRN_TEXT_LEN(&inspected_key),
881 GRN_TEXT_VALUE(&inspected_key),
882 (int)GRN_TEXT_LEN(&inspected_to_key_type),
883 GRN_TEXT_VALUE(&inspected_to_key_type),
884 (int)GRN_TEXT_LEN(from_table_name),
885 GRN_TEXT_VALUE(from_table_name),
886 (int)GRN_TEXT_LEN(from_column_name),
887 GRN_TEXT_VALUE(from_column_name),
888 (int)GRN_TEXT_LEN(to_table_name),
889 GRN_TEXT_VALUE(to_table_name),
890 (int)GRN_TEXT_LEN(to_column_name),
891 GRN_TEXT_VALUE(to_column_name));
892 GRN_OBJ_FIN(ctx, &inspected_key);
893 GRN_OBJ_FIN(ctx, &inspected_to_key_type);
894 break;
895 }
896 to_id = grn_table_add(ctx, to_table,
897 GRN_BULK_HEAD(&to_key_buffer),
898 GRN_BULK_VSIZE(&to_key_buffer),
899 NULL);
900 if (to_id == GRN_ID_NIL) {
901 continue;
902 }
903
904 GRN_BULK_REWIND(&value);
905 grn_obj_get_value(ctx, from_column, from_id, &value);
906 grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET);
907 }
908 GRN_OBJ_FIN(ctx, &from_key_buffer);
909 GRN_OBJ_FIN(ctx, &to_key_buffer);
910 GRN_OBJ_FIN(ctx, &value);
911
912 grn_table_cursor_close(ctx, cursor);
913}
914
915static grn_obj *
916command_column_copy(grn_ctx *ctx, int nargs, grn_obj **args,
917 grn_user_data *user_data)
918{
919 grn_rc rc = GRN_SUCCESS;
920 grn_obj *from_table = NULL;
921 grn_obj *from_column = NULL;
922 grn_obj *to_table = NULL;
923 grn_obj *to_column = NULL;
924 grn_obj *from_table_name;
925 grn_obj *from_column_name;
926 grn_obj *to_table_name;
927 grn_obj *to_column_name;
928
929 from_table_name = grn_plugin_proc_get_var(ctx, user_data, "from_table", -1);
930 from_column_name = grn_plugin_proc_get_var(ctx, user_data, "from_name", -1);
931 to_table_name = grn_plugin_proc_get_var(ctx, user_data, "to_table", -1);
932 to_column_name = grn_plugin_proc_get_var(ctx, user_data, "to_name", -1);
933
934 rc = command_column_copy_resolve_target(ctx, "from",
935 from_table_name, from_column_name,
936 &from_table, &from_column);
937 if (rc != GRN_SUCCESS) {
938 goto exit;
939 }
940 rc = command_column_copy_resolve_target(ctx, "to",
941 to_table_name, to_column_name,
942 &to_table, &to_column);
943 if (rc != GRN_SUCCESS) {
944 goto exit;
945 }
946
947 if ((from_table->header.type == GRN_TABLE_NO_KEY ||
948 to_table->header.type == GRN_TABLE_NO_KEY) &&
949 from_table != to_table) {
950 rc = GRN_OPERATION_NOT_SUPPORTED;
951 GRN_PLUGIN_ERROR(ctx,
952 rc,
953 "[column][copy] copy from/to TABLE_NO_KEY isn't supported: "
954 "<%.*s%c%.*s> -> <%.*s%c%.*s>",
955 (int)GRN_TEXT_LEN(from_table_name),
956 GRN_TEXT_VALUE(from_table_name),
957 GRN_DB_DELIMITER,
958 (int)GRN_TEXT_LEN(from_column_name),
959 GRN_TEXT_VALUE(from_column_name),
960 (int)GRN_TEXT_LEN(to_table_name),
961 GRN_TEXT_VALUE(to_table_name),
962 GRN_DB_DELIMITER,
963 (int)GRN_TEXT_LEN(to_column_name),
964 GRN_TEXT_VALUE(to_column_name));
965 goto exit;
966 }
967
968 if (from_table == to_table) {
969 command_column_copy_same_table(ctx, from_table, from_column, to_column);
970 } else if (from_table->header.domain == to_table->header.domain) {
971 command_column_copy_same_key_type(ctx,
972 from_table, from_column,
973 to_table, to_column);
974 } else {
975 command_column_copy_different(ctx,
976 from_table,
977 from_column,
978 to_table,
979 to_column,
980 from_table_name,
981 from_column_name,
982 to_table_name,
983 to_column_name);
984 }
985
986exit :
987 grn_ctx_output_bool(ctx, rc == GRN_SUCCESS);
988
989 if (to_column) {
990 grn_obj_unlink(ctx, to_column);
991 }
992 if (to_table) {
993 grn_obj_unlink(ctx, to_table);
994 }
995 if (from_column) {
996 grn_obj_unlink(ctx, from_column);
997 }
998 if (from_table) {
999 grn_obj_unlink(ctx, from_table);
1000 }
1001
1002 return NULL;
1003}
1004
1005void
1006grn_proc_init_column_copy(grn_ctx *ctx)
1007{
1008 grn_expr_var vars[4];
1009
1010 grn_plugin_expr_var_init(ctx, &(vars[0]), "from_table", -1);
1011 grn_plugin_expr_var_init(ctx, &(vars[1]), "from_name", -1);
1012 grn_plugin_expr_var_init(ctx, &(vars[2]), "to_table", -1);
1013 grn_plugin_expr_var_init(ctx, &(vars[3]), "to_name", -1);
1014 grn_plugin_command_create(ctx,
1015 "column_copy", -1,
1016 command_column_copy,
1017 4,
1018 vars);
1019}
1020