1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2015-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_db.h"
22
23#include <groonga/plugin.h>
24
25typedef struct {
26 grn_bool is_close_opened_object_mode;
27} grn_schema_data;
28
29static void
30command_schema_output_id(grn_ctx *ctx, grn_obj *obj)
31{
32 if (obj) {
33 grn_id id;
34 id = grn_obj_id(ctx, obj);
35 grn_ctx_output_uint64(ctx, id);
36 } else {
37 grn_ctx_output_null(ctx);
38 }
39}
40
41static void
42command_schema_output_name(grn_ctx *ctx, grn_obj *obj)
43{
44 if (obj) {
45 char name[GRN_TABLE_MAX_KEY_SIZE];
46 unsigned int name_size;
47 name_size = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
48 grn_ctx_output_str(ctx, name, name_size);
49 } else {
50 grn_ctx_output_null(ctx);
51 }
52}
53
54static void
55command_schema_output_column_name(grn_ctx *ctx, grn_obj *column)
56{
57 char name[GRN_TABLE_MAX_KEY_SIZE];
58 unsigned int name_size;
59 name_size = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
60 grn_ctx_output_str(ctx, name, name_size);
61}
62
63static void
64command_schema_output_type(grn_ctx *ctx, const char *type_label, grn_obj *type)
65{
66 if (!type) {
67 grn_ctx_output_null(ctx);
68 return;
69 }
70
71 grn_ctx_output_map_open(ctx, type_label, 3);
72
73 grn_ctx_output_cstr(ctx, "id");
74 command_schema_output_id(ctx, type);
75
76 grn_ctx_output_cstr(ctx, "name");
77 command_schema_output_name(ctx, type);
78
79 grn_ctx_output_cstr(ctx, "type");
80 if (grn_obj_is_table(ctx, type)) {
81 grn_ctx_output_cstr(ctx, "reference");
82 } else {
83 grn_ctx_output_cstr(ctx, "type");
84 }
85 grn_ctx_output_map_close(ctx);
86}
87
88static void
89command_schema_output_key_type(grn_ctx *ctx, grn_obj *key_type)
90{
91 command_schema_output_type(ctx, "key_type", key_type);
92}
93
94static void
95command_schema_output_value_type(grn_ctx *ctx, grn_obj *value_type)
96{
97 command_schema_output_type(ctx, "value_type", value_type);
98}
99
100static void
101command_schema_output_command(grn_ctx *ctx,
102 const char *command_name,
103 grn_obj *arguments)
104{
105 grn_ctx_output_map_open(ctx, "command", 3);
106
107 grn_ctx_output_cstr(ctx, "name");
108 grn_ctx_output_cstr(ctx, command_name);
109
110 grn_ctx_output_cstr(ctx, "arguments");
111 {
112 int i, n;
113
114 n = grn_vector_size(ctx, arguments);
115 grn_ctx_output_map_open(ctx, "arguments", n / 2);
116 for (i = 0; i < n; i += 2) {
117 const char *name;
118 unsigned int name_size;
119 const char *value;
120 unsigned int value_size;
121
122 name_size = grn_vector_get_element(ctx, arguments, i, &name,
123 NULL, NULL);
124 value_size = grn_vector_get_element(ctx, arguments, i + 1, &value,
125 NULL, NULL);
126 grn_ctx_output_str(ctx, name, name_size);
127 grn_ctx_output_str(ctx, value, value_size);
128 }
129 grn_ctx_output_map_close(ctx);
130 }
131
132 grn_ctx_output_cstr(ctx, "command_line");
133 {
134 int i, n;
135 grn_obj command_line;
136
137 GRN_TEXT_INIT(&command_line, 0);
138 GRN_TEXT_PUTS(ctx, &command_line, command_name);
139 n = grn_vector_size(ctx, arguments);
140 for (i = 0; i < n; i += 2) {
141 const char *name;
142 unsigned int name_size;
143 const char *value;
144 unsigned int value_size;
145
146 name_size = grn_vector_get_element(ctx, arguments, i, &name,
147 NULL, NULL);
148 value_size = grn_vector_get_element(ctx, arguments, i + 1, &value,
149 NULL, NULL);
150 grn_text_printf(ctx, &command_line,
151 " --%.*s %.*s",
152 name_size, name,
153 value_size, value);
154 }
155 grn_ctx_output_str(ctx,
156 GRN_TEXT_VALUE(&command_line),
157 GRN_TEXT_LEN(&command_line));
158 GRN_OBJ_FIN(ctx, &command_line);
159 }
160
161 grn_ctx_output_map_close(ctx);
162}
163
164static void
165command_schema_output_plugins(grn_ctx *ctx)
166{
167 grn_obj plugin_names;
168 unsigned int i, n;
169
170 GRN_TEXT_INIT(&plugin_names, GRN_OBJ_VECTOR);
171
172 grn_plugin_get_names(ctx, &plugin_names);
173
174 grn_ctx_output_cstr(ctx, "plugins");
175
176 n = grn_vector_size(ctx, &plugin_names);
177 grn_ctx_output_map_open(ctx, "plugins", n);
178 for (i = 0; i < n; i++) {
179 const char *name;
180 unsigned int name_size;
181
182 name_size = grn_vector_get_element(ctx, &plugin_names, i, &name, NULL, NULL);
183 grn_ctx_output_str(ctx, name, name_size);
184
185 grn_ctx_output_map_open(ctx, "plugin", 1);
186 grn_ctx_output_cstr(ctx, "name");
187 grn_ctx_output_str(ctx, name, name_size);
188 grn_ctx_output_map_close(ctx);
189 }
190 grn_ctx_output_map_close(ctx);
191
192 GRN_OBJ_FIN(ctx, &plugin_names);
193}
194
195static void
196command_schema_output_types(grn_ctx *ctx)
197{
198 unsigned int n_types;
199
200 n_types = 0;
201 GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
202 if (grn_id_is_builtin_type(ctx, id)) {
203 n_types++;
204 }
205 } GRN_DB_EACH_END(ctx, cursor);
206
207 grn_ctx_output_cstr(ctx, "types");
208
209 grn_ctx_output_map_open(ctx, "types", n_types);
210 GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
211 grn_obj *type;
212
213 if (!grn_id_is_builtin_type(ctx, id)) {
214 continue;
215 }
216
217 type = grn_ctx_at(ctx, id);
218
219 command_schema_output_name(ctx, type);
220
221 grn_ctx_output_map_open(ctx, "type", 5);
222
223 grn_ctx_output_cstr(ctx, "id");
224 command_schema_output_id(ctx, type);
225
226 grn_ctx_output_cstr(ctx, "name");
227 command_schema_output_name(ctx, type);
228
229 grn_ctx_output_cstr(ctx, "size");
230 grn_ctx_output_int64(ctx, grn_type_size(ctx, type));
231
232 grn_ctx_output_cstr(ctx, "can_be_key_type");
233 grn_ctx_output_bool(ctx, grn_type_size(ctx, type) <= GRN_TABLE_MAX_KEY_SIZE);
234
235 grn_ctx_output_cstr(ctx, "can_be_value_type");
236 grn_ctx_output_bool(ctx, !(type->header.flags & GRN_OBJ_KEY_VAR_SIZE));
237
238 grn_ctx_output_map_close(ctx);
239 } GRN_DB_EACH_END(ctx, cursor);
240 grn_ctx_output_map_close(ctx);
241}
242
243static void
244command_schema_output_tokenizers(grn_ctx *ctx, grn_schema_data *data)
245{
246 grn_obj tokenizer_ids;
247 unsigned int i, n;
248
249 GRN_RECORD_INIT(&tokenizer_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
250 GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
251 void *name;
252 int name_size;
253 grn_obj *object;
254
255 name_size = grn_table_cursor_get_key(ctx, cursor, &name);
256 if (grn_obj_name_is_column(ctx, name, name_size)) {
257 continue;
258 }
259
260 if (data->is_close_opened_object_mode) {
261 grn_ctx_push_temporary_open_space(ctx);
262 }
263
264 object = grn_ctx_at(ctx, id);
265 if (object) {
266 if (grn_obj_is_tokenizer_proc(ctx, object)) {
267 GRN_RECORD_PUT(ctx, &tokenizer_ids, id);
268 }
269 } else {
270 /* XXX: this clause is executed when MeCab tokenizer is enabled in
271 database but the groonga isn't supported MeCab.
272 We should return error mesage about it and error exit status
273 but it's too difficult for this architecture. :< */
274 GRN_PLUGIN_CLEAR_ERROR(ctx);
275 }
276
277 if (data->is_close_opened_object_mode) {
278 grn_ctx_pop_temporary_open_space(ctx);
279 }
280 } GRN_DB_EACH_END(ctx, cursor);
281
282 grn_ctx_output_cstr(ctx, "tokenizers");
283
284 n = GRN_BULK_VSIZE(&tokenizer_ids) / sizeof(grn_id);
285 grn_ctx_output_map_open(ctx, "tokenizers", n);
286 for (i = 0; i < n; i++) {
287 grn_id tokenizer_id;
288 grn_obj *tokenizer;
289
290 tokenizer_id = GRN_RECORD_VALUE_AT(&tokenizer_ids, i);
291 tokenizer = grn_ctx_at(ctx, tokenizer_id);
292
293 command_schema_output_name(ctx, tokenizer);
294
295 grn_ctx_output_map_open(ctx, "tokenizer", 2);
296
297 grn_ctx_output_cstr(ctx, "id");
298 command_schema_output_id(ctx, tokenizer);
299
300 grn_ctx_output_cstr(ctx, "name");
301 command_schema_output_name(ctx, tokenizer);
302
303 grn_ctx_output_map_close(ctx);
304 }
305 grn_ctx_output_map_close(ctx);
306
307 GRN_OBJ_FIN(ctx, &tokenizer_ids);
308}
309
310static void
311command_schema_output_normalizers(grn_ctx *ctx, grn_schema_data *data)
312{
313 grn_obj normalizer_ids;
314 unsigned int i, n;
315
316 GRN_RECORD_INIT(&normalizer_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
317 GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
318 void *name;
319 int name_size;
320 grn_obj *object;
321
322 name_size = grn_table_cursor_get_key(ctx, cursor, &name);
323 if (grn_obj_name_is_column(ctx, name, name_size)) {
324 continue;
325 }
326
327 if (data->is_close_opened_object_mode) {
328 grn_ctx_push_temporary_open_space(ctx);
329 }
330
331 object = grn_ctx_at(ctx, id);
332 if (object) {
333 if (grn_obj_is_normalizer_proc(ctx, object)) {
334 GRN_RECORD_PUT(ctx, &normalizer_ids, id);
335 }
336 } else {
337 /* XXX: this clause is executed when MeCab normalizer is enabled in
338 database but the groonga isn't supported MeCab.
339 We should return error mesage about it and error exit status
340 but it's too difficult for this architecture. :< */
341 GRN_PLUGIN_CLEAR_ERROR(ctx);
342 }
343
344 if (data->is_close_opened_object_mode) {
345 grn_ctx_pop_temporary_open_space(ctx);
346 }
347 } GRN_DB_EACH_END(ctx, cursor);
348
349 grn_ctx_output_cstr(ctx, "normalizers");
350
351 n = GRN_BULK_VSIZE(&normalizer_ids) / sizeof(grn_id);
352 grn_ctx_output_map_open(ctx, "normalizers", n);
353 for (i = 0; i < n; i++) {
354 grn_id normalizer_id;
355 grn_obj *normalizer;
356
357 normalizer_id = GRN_RECORD_VALUE_AT(&normalizer_ids, i);
358 normalizer = grn_ctx_at(ctx, normalizer_id);
359
360 command_schema_output_name(ctx, normalizer);
361
362 grn_ctx_output_map_open(ctx, "normalizer", 2);
363
364 grn_ctx_output_cstr(ctx, "id");
365 command_schema_output_id(ctx, normalizer);
366
367 grn_ctx_output_cstr(ctx, "name");
368 command_schema_output_name(ctx, normalizer);
369
370 grn_ctx_output_map_close(ctx);
371 }
372 grn_ctx_output_map_close(ctx);
373
374 GRN_OBJ_FIN(ctx, &normalizer_ids);
375}
376
377static void
378command_schema_output_token_filters(grn_ctx *ctx, grn_schema_data *data)
379{
380 grn_obj token_filter_ids;
381 unsigned int i, n;
382
383 GRN_RECORD_INIT(&token_filter_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
384 GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
385 void *name;
386 int name_size;
387 grn_obj *object;
388
389 name_size = grn_table_cursor_get_key(ctx, cursor, &name);
390 if (grn_obj_name_is_column(ctx, name, name_size)) {
391 continue;
392 }
393
394 if (data->is_close_opened_object_mode) {
395 grn_ctx_push_temporary_open_space(ctx);
396 }
397
398 object = grn_ctx_at(ctx, id);
399 if (object) {
400 if (grn_obj_is_token_filter_proc(ctx, object)) {
401 GRN_RECORD_PUT(ctx, &token_filter_ids, id);
402 }
403 } else {
404 /* XXX: this clause is executed when MeCab normalizer is enabled in
405 database but the groonga isn't supported MeCab.
406 We should return error mesage about it and error exit status
407 but it's too difficult for this architecture. :< */
408 GRN_PLUGIN_CLEAR_ERROR(ctx);
409 }
410
411 if (data->is_close_opened_object_mode) {
412 grn_ctx_pop_temporary_open_space(ctx);
413 }
414 } GRN_DB_EACH_END(ctx, cursor);
415
416 grn_ctx_output_cstr(ctx, "token_filters");
417
418 n = GRN_BULK_VSIZE(&token_filter_ids) / sizeof(grn_id);
419 grn_ctx_output_map_open(ctx, "token_filters", n);
420 for (i = 0; i < n; i++) {
421 grn_id token_filter_id;
422 grn_obj *token_filter;
423
424 token_filter_id = GRN_RECORD_VALUE_AT(&token_filter_ids, i);
425 token_filter = grn_ctx_at(ctx, token_filter_id);
426
427 command_schema_output_name(ctx, token_filter);
428
429 grn_ctx_output_map_open(ctx, "token_filter", 2);
430
431 grn_ctx_output_cstr(ctx, "id");
432 command_schema_output_id(ctx, token_filter);
433
434 grn_ctx_output_cstr(ctx, "name");
435 command_schema_output_name(ctx, token_filter);
436
437 grn_ctx_output_map_close(ctx);
438 }
439 grn_ctx_output_map_close(ctx);
440
441 GRN_OBJ_FIN(ctx, &token_filter_ids);
442}
443
444static const char *
445command_schema_table_type_name(grn_ctx *ctx, grn_obj *table)
446{
447 const char *name = "unknown";
448
449 switch (table->header.type) {
450 case GRN_TABLE_NO_KEY :
451 name = "array";
452 break;
453 case GRN_TABLE_HASH_KEY :
454 name = "hash table";
455 break;
456 case GRN_TABLE_PAT_KEY :
457 name = "patricia trie";
458 break;
459 case GRN_TABLE_DAT_KEY :
460 name = "double array trie";
461 break;
462 default :
463 break;
464 }
465
466 return name;
467}
468
469static void
470command_schema_table_output_key_type(grn_ctx *ctx, grn_obj *table)
471{
472 grn_obj *key_type = NULL;
473
474 if (table->header.type != GRN_TABLE_NO_KEY &&
475 table->header.domain != GRN_ID_NIL) {
476 key_type = grn_ctx_at(ctx, table->header.domain);
477 }
478
479 command_schema_output_key_type(ctx, key_type);
480}
481
482static void
483command_schema_table_output_value_type(grn_ctx *ctx, grn_obj *table)
484{
485 grn_obj *value_type = NULL;
486 grn_id range = GRN_ID_NIL;
487
488 if (table->header.type != GRN_TABLE_DAT_KEY) {
489 range = grn_obj_get_range(ctx, table);
490 }
491 if (range != GRN_ID_NIL) {
492 value_type = grn_ctx_at(ctx, range);
493 }
494
495 command_schema_output_value_type(ctx, value_type);
496}
497
498static void
499command_schema_table_output_tokenizer(grn_ctx *ctx, grn_obj *table)
500{
501 grn_obj *tokenizer;
502
503 tokenizer = grn_obj_get_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, NULL);
504 if (!tokenizer) {
505 grn_ctx_output_null(ctx);
506 return;
507 }
508
509 grn_ctx_output_map_open(ctx, "tokenizer", 2);
510
511 grn_ctx_output_cstr(ctx, "id");
512 command_schema_output_id(ctx, tokenizer);
513
514 grn_ctx_output_cstr(ctx, "name");
515 command_schema_output_name(ctx, tokenizer);
516
517 grn_ctx_output_map_close(ctx);
518}
519
520static void
521command_schema_table_output_normalizer(grn_ctx *ctx, grn_obj *table)
522{
523 grn_obj *normalizer;
524
525 normalizer = grn_obj_get_info(ctx, table, GRN_INFO_NORMALIZER, NULL);
526 if (!normalizer) {
527 grn_ctx_output_null(ctx);
528 return;
529 }
530
531 grn_ctx_output_map_open(ctx, "normalizer", 2);
532
533 grn_ctx_output_cstr(ctx, "id");
534 command_schema_output_id(ctx, normalizer);
535
536 grn_ctx_output_cstr(ctx, "name");
537 command_schema_output_name(ctx, normalizer);
538
539 grn_ctx_output_map_close(ctx);
540}
541
542static void
543command_schema_table_output_token_filters(grn_ctx *ctx, grn_obj *table)
544{
545 grn_obj token_filters;
546 int i, n;
547
548 GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, GRN_DB_OBJECT);
549 if (table->header.type != GRN_TABLE_NO_KEY) {
550 grn_obj_get_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
551 }
552
553 n = GRN_BULK_VSIZE(&token_filters) / sizeof(grn_obj *);
554 grn_ctx_output_array_open(ctx, "token_filters", n);
555 for (i = 0; i < n; i++) {
556 grn_obj *token_filter;
557
558 token_filter = GRN_PTR_VALUE_AT(&token_filters, i);
559
560 grn_ctx_output_map_open(ctx, "token_filter", 2);
561
562 grn_ctx_output_cstr(ctx, "id");
563 command_schema_output_id(ctx, token_filter);
564
565 grn_ctx_output_cstr(ctx, "name");
566 command_schema_output_name(ctx, token_filter);
567
568 grn_ctx_output_map_close(ctx);
569 }
570 grn_ctx_output_array_close(ctx);
571
572 GRN_OBJ_FIN(ctx, &token_filters);
573}
574
575static void
576command_schema_table_command_collect_arguments(grn_ctx *ctx,
577 grn_obj *table,
578 grn_obj *arguments)
579{
580#define ADD(name_, value_) \
581 grn_vector_add_element(ctx, arguments, \
582 name_, strlen(name_), \
583 0, GRN_DB_TEXT); \
584 grn_vector_add_element(ctx, arguments, \
585 value_, strlen(value_), \
586 0, GRN_DB_TEXT)
587
588#define ADD_OBJECT_NAME(name_, object_) do { \
589 char object_name[GRN_TABLE_MAX_KEY_SIZE]; \
590 unsigned int object_name_size; \
591 object_name_size = grn_obj_name(ctx, object_, \
592 object_name, \
593 GRN_TABLE_MAX_KEY_SIZE); \
594 object_name[object_name_size] = '\0'; \
595 ADD(name_, object_name); \
596 } while (GRN_FALSE)
597
598 ADD_OBJECT_NAME("name", table);
599
600 {
601 grn_obj flags;
602 grn_table_flags table_flags;
603 grn_table_flags ignored_flags = GRN_OBJ_KEY_NORMALIZE | GRN_OBJ_PERSISTENT;
604 GRN_TEXT_INIT(&flags, 0);
605 grn_table_get_info(ctx, table, &table_flags, NULL, NULL, NULL, NULL);
606 grn_dump_table_create_flags(ctx,
607 table_flags & ~ignored_flags,
608 &flags);
609 GRN_TEXT_PUTC(ctx, &flags, '\0');
610 ADD("flags", GRN_TEXT_VALUE(&flags));
611 GRN_OBJ_FIN(ctx, &flags);
612 }
613
614 {
615 grn_obj *key_type = NULL;
616
617 if (table->header.type != GRN_TABLE_NO_KEY &&
618 table->header.domain != GRN_ID_NIL) {
619 key_type = grn_ctx_at(ctx, table->header.domain);
620 }
621 if (key_type) {
622 ADD_OBJECT_NAME("key_type", key_type);
623 }
624 }
625
626 {
627 grn_obj *value_type = NULL;
628 grn_id range = GRN_ID_NIL;
629
630 if (table->header.type != GRN_TABLE_DAT_KEY) {
631 range = grn_obj_get_range(ctx, table);
632 }
633 if (range != GRN_ID_NIL) {
634 value_type = grn_ctx_at(ctx, range);
635 }
636 if (value_type) {
637 ADD_OBJECT_NAME("value_type", value_type);
638 }
639 }
640
641 {
642 grn_obj *tokenizer;
643 tokenizer = grn_obj_get_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, NULL);
644 if (tokenizer) {
645 ADD_OBJECT_NAME("default_tokenizer", tokenizer);
646 }
647 }
648
649 {
650 grn_obj *normalizer;
651 normalizer = grn_obj_get_info(ctx, table, GRN_INFO_NORMALIZER, NULL);
652 if (!normalizer && (table->header.flags & GRN_OBJ_KEY_NORMALIZE)) {
653 normalizer = grn_ctx_get(ctx, "NormalizerAuto", -1);
654 }
655 if (normalizer) {
656 ADD_OBJECT_NAME("normalizer", normalizer);
657 }
658 }
659
660 if (table->header.type != GRN_TABLE_NO_KEY) {
661 grn_obj token_filters;
662 int n;
663
664 GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, GRN_DB_OBJECT);
665 grn_obj_get_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
666 n = GRN_BULK_VSIZE(&token_filters) / sizeof(grn_obj *);
667 if (n > 0) {
668 grn_obj token_filter_names;
669 int i;
670
671 GRN_TEXT_INIT(&token_filter_names, 0);
672 for (i = 0; i < n; i++) {
673 grn_obj *token_filter;
674 char name[GRN_TABLE_MAX_KEY_SIZE];
675 int name_size;
676
677 token_filter = GRN_PTR_VALUE_AT(&token_filters, i);
678 name_size = grn_obj_name(ctx, token_filter,
679 name, GRN_TABLE_MAX_KEY_SIZE);
680 if (i > 0) {
681 GRN_TEXT_PUTC(ctx, &token_filter_names, ',');
682 }
683 GRN_TEXT_PUT(ctx, &token_filter_names, name, name_size);
684 }
685 GRN_TEXT_PUTC(ctx, &token_filter_names, '\0');
686 ADD("token_filters", GRN_TEXT_VALUE(&token_filter_names));
687 GRN_OBJ_FIN(ctx, &token_filter_names);
688 }
689 GRN_OBJ_FIN(ctx, &token_filters);
690 }
691
692#undef ADD_OBJECT_NAME
693#undef ADD
694}
695
696static void
697command_schema_table_output_command(grn_ctx *ctx, grn_obj *table)
698{
699 grn_obj arguments;
700
701 GRN_TEXT_INIT(&arguments, GRN_OBJ_VECTOR);
702 command_schema_table_command_collect_arguments(ctx, table, &arguments);
703
704 command_schema_output_command(ctx, "table_create", &arguments);
705
706 GRN_OBJ_FIN(ctx, &arguments);
707}
708
709static void
710command_schema_column_output_type(grn_ctx *ctx, grn_obj *column)
711{
712 switch (column->header.type) {
713 case GRN_COLUMN_FIX_SIZE :
714 case GRN_COLUMN_VAR_SIZE :
715 switch (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
716 case GRN_OBJ_COLUMN_SCALAR :
717 grn_ctx_output_cstr(ctx, "scalar");
718 break;
719 case GRN_OBJ_COLUMN_VECTOR :
720 grn_ctx_output_cstr(ctx, "vector");
721 break;
722 }
723 break;
724 case GRN_COLUMN_INDEX :
725 grn_ctx_output_cstr(ctx, "index");
726 break;
727 }
728}
729
730static void
731command_schema_column_output_value_type(grn_ctx *ctx, grn_obj *column)
732{
733 grn_obj *value_type;
734 value_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
735 command_schema_output_value_type(ctx, value_type);
736}
737
738static void
739command_schema_column_output_compress(grn_ctx *ctx, grn_obj *column)
740{
741 const char *compress = NULL;
742
743 if (column->header.type != GRN_COLUMN_INDEX) {
744 switch (column->header.flags & GRN_OBJ_COMPRESS_MASK) {
745 case GRN_OBJ_COMPRESS_ZLIB :
746 compress = "zlib";
747 break;
748 case GRN_OBJ_COMPRESS_LZ4 :
749 compress = "lz4";
750 break;
751 case GRN_OBJ_COMPRESS_ZSTD :
752 compress = "zstd";
753 break;
754 default :
755 break;
756 }
757 }
758
759 if (compress) {
760 grn_ctx_output_cstr(ctx, compress);
761 } else {
762 grn_ctx_output_null(ctx);
763 }
764}
765
766static void
767command_schema_column_output_sources(grn_ctx *ctx, grn_obj *column)
768{
769 grn_obj *source_table;
770 grn_obj source_ids;
771 unsigned int i, n_ids;
772
773 source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
774
775 GRN_RECORD_INIT(&source_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
776
777 if (column->header.type == GRN_COLUMN_INDEX) {
778 grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
779 }
780
781 n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
782 grn_ctx_output_array_open(ctx, "sources", n_ids);
783 for (i = 0; i < n_ids; i++) {
784 grn_id source_id;
785 grn_obj *source;
786
787 source_id = GRN_RECORD_VALUE_AT(&source_ids, i);
788 source = grn_ctx_at(ctx, source_id);
789
790 grn_ctx_output_map_open(ctx, "source", 4);
791
792 grn_ctx_output_cstr(ctx, "id");
793 if (grn_obj_is_table(ctx, source)) {
794 command_schema_output_id(ctx, NULL);
795 } else {
796 command_schema_output_id(ctx, source);
797 }
798
799 grn_ctx_output_cstr(ctx, "name");
800 if (grn_obj_is_table(ctx, source)) {
801 grn_ctx_output_cstr(ctx, "_key");
802 } else {
803 command_schema_output_column_name(ctx, source);
804 }
805
806 grn_ctx_output_cstr(ctx, "table");
807 command_schema_output_name(ctx, source_table);
808
809 grn_ctx_output_cstr(ctx, "full_name");
810 if (grn_obj_is_table(ctx, source)) {
811 char name[GRN_TABLE_MAX_KEY_SIZE];
812 unsigned int name_size;
813 name_size = grn_obj_name(ctx, source, name, GRN_TABLE_MAX_KEY_SIZE);
814 name[name_size] = '\0';
815 grn_strcat(name, GRN_TABLE_MAX_KEY_SIZE, "._key");
816 grn_ctx_output_cstr(ctx, name);
817 } else {
818 command_schema_output_name(ctx, source);
819 }
820
821 grn_ctx_output_map_close(ctx);
822 }
823 grn_ctx_output_array_close(ctx);
824
825 GRN_OBJ_FIN(ctx, &source_ids);
826}
827
828static void
829command_schema_output_indexes(grn_ctx *ctx, grn_obj *object)
830{
831 uint32_t i;
832 grn_index_datum *index_data = NULL;
833 uint32_t n_index_data = 0;
834
835 n_index_data = grn_column_get_all_index_data(ctx, object, NULL, 0);
836 if (n_index_data > 0) {
837 index_data = GRN_PLUGIN_MALLOC(ctx,
838 sizeof(grn_index_datum) * n_index_data);
839 if (!index_data) {
840 GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
841 "[schema] failed to allocate memory for indexes");
842 return;
843 }
844 grn_column_get_all_index_data(ctx, object, index_data, n_index_data);
845 }
846
847 grn_ctx_output_array_open(ctx, "indexes", n_index_data);
848 for (i = 0; i < n_index_data; i++) {
849 grn_obj *lexicon;
850
851 grn_ctx_output_map_open(ctx, "index", 5);
852
853 grn_ctx_output_cstr(ctx, "id");
854 command_schema_output_id(ctx, index_data[i].index);
855
856 grn_ctx_output_cstr(ctx, "full_name");
857 command_schema_output_name(ctx, index_data[i].index);
858
859 grn_ctx_output_cstr(ctx, "table");
860 lexicon = grn_ctx_at(ctx, index_data[i].index->header.domain);
861 command_schema_output_name(ctx, lexicon);
862
863 grn_ctx_output_cstr(ctx, "name");
864 command_schema_output_column_name(ctx, index_data[i].index);
865
866 grn_ctx_output_cstr(ctx, "section");
867 grn_ctx_output_uint64(ctx, index_data[i].section);
868
869 grn_ctx_output_map_close(ctx);
870 }
871 grn_ctx_output_array_close(ctx);
872
873 if (index_data) {
874 GRN_PLUGIN_FREE(ctx, index_data);
875 }
876}
877
878static void
879command_schema_column_command_collect_arguments(grn_ctx *ctx,
880 grn_obj *table,
881 grn_obj *column,
882 grn_obj *arguments)
883{
884#define ADD(name_, value_) \
885 grn_vector_add_element(ctx, arguments, \
886 name_, strlen(name_), \
887 0, GRN_DB_TEXT); \
888 grn_vector_add_element(ctx, arguments, \
889 value_, strlen(value_), \
890 0, GRN_DB_TEXT)
891
892#define ADD_OBJECT_NAME(name_, object_) do { \
893 char object_name[GRN_TABLE_MAX_KEY_SIZE]; \
894 unsigned int object_name_size; \
895 object_name_size = grn_obj_name(ctx, object_, \
896 object_name, \
897 GRN_TABLE_MAX_KEY_SIZE); \
898 object_name[object_name_size] = '\0'; \
899 ADD(name_, object_name); \
900 } while (GRN_FALSE)
901
902 ADD_OBJECT_NAME("table", table);
903 {
904 char column_name[GRN_TABLE_MAX_KEY_SIZE];
905 unsigned int column_name_size;
906 column_name_size = grn_column_name(ctx, column,
907 column_name, GRN_TABLE_MAX_KEY_SIZE);
908 column_name[column_name_size] = '\0';
909 ADD("name", column_name);
910 }
911
912 {
913 grn_obj flags;
914 grn_column_flags column_flags;
915
916 GRN_TEXT_INIT(&flags, 0);
917 column_flags = grn_column_get_flags(ctx, column);
918 grn_dump_column_create_flags(ctx,
919 column_flags & ~GRN_OBJ_PERSISTENT,
920 &flags);
921 GRN_TEXT_PUTC(ctx, &flags, '\0');
922 ADD("flags", GRN_TEXT_VALUE(&flags));
923 GRN_OBJ_FIN(ctx, &flags);
924 }
925
926 {
927 grn_obj *value_type;
928
929 value_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
930 ADD_OBJECT_NAME("type", value_type);
931 }
932
933 if (column->header.type == GRN_COLUMN_INDEX) {
934 grn_obj source_ids;
935 unsigned int n_ids;
936
937 GRN_RECORD_INIT(&source_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
938 grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
939
940 n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
941 if (n_ids > 0) {
942 grn_obj sources;
943 unsigned int i;
944
945 GRN_TEXT_INIT(&sources, 0);
946 for (i = 0; i < n_ids; i++) {
947 grn_id source_id;
948 grn_obj *source;
949 char name[GRN_TABLE_MAX_KEY_SIZE];
950 unsigned int name_size;
951
952 source_id = GRN_RECORD_VALUE_AT(&source_ids, i);
953 source = grn_ctx_at(ctx, source_id);
954
955 if (grn_obj_is_table(ctx, source)) {
956 grn_strcpy(name, GRN_TABLE_MAX_KEY_SIZE, "_key");
957 name_size = strlen(name);
958 } else {
959 name_size = grn_column_name(ctx, source, name, GRN_TABLE_MAX_KEY_SIZE);
960 }
961 if (i > 0) {
962 GRN_TEXT_PUTC(ctx, &sources, ',');
963 }
964 GRN_TEXT_PUT(ctx, &sources, name, name_size);
965 }
966 GRN_TEXT_PUTC(ctx, &sources, '\0');
967 ADD("source", GRN_TEXT_VALUE(&sources));
968 GRN_OBJ_FIN(ctx, &sources);
969 }
970 GRN_OBJ_FIN(ctx, &source_ids);
971 }
972
973#undef ADD_OBJECT_NAME
974#undef ADD
975}
976
977static void
978command_schema_column_output_command(grn_ctx *ctx,
979 grn_obj *table,
980 grn_obj *column)
981{
982 grn_obj arguments;
983
984 GRN_TEXT_INIT(&arguments, GRN_OBJ_VECTOR);
985 command_schema_column_command_collect_arguments(ctx, table, column, &arguments);
986
987 command_schema_output_command(ctx, "column_create", &arguments);
988
989 GRN_OBJ_FIN(ctx, &arguments);
990}
991
992static void
993command_schema_column_output(grn_ctx *ctx, grn_obj *table, grn_obj *column)
994{
995 if (!column) {
996 return;
997 }
998
999 command_schema_output_column_name(ctx, column);
1000
1001 grn_ctx_output_map_open(ctx, "column", 13);
1002
1003 grn_ctx_output_cstr(ctx, "id");
1004 command_schema_output_id(ctx, column);
1005
1006 grn_ctx_output_cstr(ctx, "name");
1007 command_schema_output_column_name(ctx, column);
1008
1009 grn_ctx_output_cstr(ctx, "table");
1010 command_schema_output_name(ctx, table);
1011
1012 grn_ctx_output_cstr(ctx, "full_name");
1013 command_schema_output_name(ctx, column);
1014
1015 grn_ctx_output_cstr(ctx, "type");
1016 command_schema_column_output_type(ctx, column);
1017
1018 grn_ctx_output_cstr(ctx, "value_type");
1019 command_schema_column_output_value_type(ctx, column);
1020
1021 grn_ctx_output_cstr(ctx, "compress");
1022 command_schema_column_output_compress(ctx, column);
1023
1024 grn_ctx_output_cstr(ctx, "section");
1025 grn_ctx_output_bool(ctx, (column->header.flags & GRN_OBJ_WITH_SECTION) != 0);
1026
1027 grn_ctx_output_cstr(ctx, "weight");
1028 grn_ctx_output_bool(ctx, (column->header.flags & GRN_OBJ_WITH_WEIGHT) != 0);
1029
1030 grn_ctx_output_cstr(ctx, "position");
1031 grn_ctx_output_bool(ctx, (column->header.flags & GRN_OBJ_WITH_POSITION) != 0);
1032
1033 grn_ctx_output_cstr(ctx, "sources");
1034 command_schema_column_output_sources(ctx, column);
1035
1036 grn_ctx_output_cstr(ctx, "indexes");
1037 command_schema_output_indexes(ctx, column);
1038
1039 grn_ctx_output_cstr(ctx, "command");
1040 command_schema_column_output_command(ctx, table, column);
1041
1042 grn_ctx_output_map_close(ctx);
1043}
1044
1045static void
1046command_schema_table_output_columns(grn_ctx *ctx,
1047 grn_obj *table,
1048 grn_schema_data *data)
1049{
1050 grn_hash *columns;
1051
1052 columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
1053 GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
1054 if (!columns) {
1055 grn_ctx_output_map_open(ctx, "columns", 0);
1056 grn_ctx_output_map_close(ctx);
1057 return;
1058 }
1059
1060 grn_table_columns(ctx, table, "", 0, (grn_obj *)columns);
1061 grn_ctx_output_map_open(ctx, "columns", grn_hash_size(ctx, columns));
1062 {
1063 grn_id *key;
1064 GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
1065 grn_obj *column;
1066
1067 if (data->is_close_opened_object_mode) {
1068 grn_ctx_push_temporary_open_space(ctx);
1069 }
1070
1071 column = grn_ctx_at(ctx, *key);
1072 command_schema_column_output(ctx, table, column);
1073
1074 if (data->is_close_opened_object_mode) {
1075 grn_ctx_pop_temporary_open_space(ctx);
1076 }
1077 });
1078 }
1079 grn_ctx_output_map_close(ctx);
1080 grn_hash_close(ctx, columns);
1081}
1082
1083static void
1084command_schema_output_table(grn_ctx *ctx,
1085 grn_schema_data *data,
1086 grn_obj *table)
1087{
1088 command_schema_output_name(ctx, table);
1089
1090 grn_ctx_output_map_open(ctx, "table", 11);
1091
1092 grn_ctx_output_cstr(ctx, "id");
1093 command_schema_output_id(ctx, table);
1094
1095 grn_ctx_output_cstr(ctx, "name");
1096 command_schema_output_name(ctx, table);
1097
1098 grn_ctx_output_cstr(ctx, "type");
1099 grn_ctx_output_cstr(ctx, command_schema_table_type_name(ctx, table));
1100
1101 grn_ctx_output_cstr(ctx, "key_type");
1102 command_schema_table_output_key_type(ctx, table);
1103
1104 grn_ctx_output_cstr(ctx, "value_type");
1105 command_schema_table_output_value_type(ctx, table);
1106
1107 grn_ctx_output_cstr(ctx, "tokenizer");
1108 command_schema_table_output_tokenizer(ctx, table);
1109
1110 grn_ctx_output_cstr(ctx, "normalizer");
1111 command_schema_table_output_normalizer(ctx, table);
1112
1113 grn_ctx_output_cstr(ctx, "token_filters");
1114 command_schema_table_output_token_filters(ctx, table);
1115
1116 grn_ctx_output_cstr(ctx, "indexes");
1117 command_schema_output_indexes(ctx, table);
1118
1119 grn_ctx_output_cstr(ctx, "command");
1120 command_schema_table_output_command(ctx, table);
1121
1122 grn_ctx_output_cstr(ctx, "columns");
1123 command_schema_table_output_columns(ctx, table, data);
1124
1125 grn_ctx_output_map_close(ctx);
1126}
1127
1128static void
1129command_schema_output_tables(grn_ctx *ctx, grn_schema_data *data)
1130{
1131 grn_obj table_ids;
1132 unsigned int i, n;
1133
1134 GRN_RECORD_INIT(&table_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
1135 GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
1136 void *name;
1137 int name_size;
1138 grn_obj *object;
1139
1140 if (grn_id_is_builtin(ctx, id)) {
1141 continue;
1142 }
1143
1144 name_size = grn_table_cursor_get_key(ctx, cursor, &name);
1145 if (grn_obj_name_is_column(ctx, name, name_size)) {
1146 continue;
1147 }
1148
1149 if (data->is_close_opened_object_mode) {
1150 grn_ctx_push_temporary_open_space(ctx);
1151 }
1152
1153 object = grn_ctx_at(ctx, id);
1154 if (!object) {
1155 /* XXX: this clause is executed when MeCab tokenizer is enabled in
1156 database but the groonga isn't supported MeCab.
1157 We should return error mesage about it and error exit status
1158 but it's too difficult for this architecture. :< */
1159 GRN_PLUGIN_CLEAR_ERROR(ctx);
1160 goto next_loop;
1161 }
1162
1163 if (grn_obj_is_table(ctx, object)) {
1164 GRN_RECORD_PUT(ctx, &table_ids, id);
1165 }
1166
1167 next_loop :
1168 if (data->is_close_opened_object_mode) {
1169 grn_ctx_pop_temporary_open_space(ctx);
1170 }
1171 } GRN_TABLE_EACH_END(ctx, cursor);
1172
1173 n = GRN_BULK_VSIZE(&table_ids) / sizeof(grn_id);
1174
1175 grn_ctx_output_cstr(ctx, "tables");
1176 grn_ctx_output_map_open(ctx, "tables", n);
1177 for (i = 0; i < n; i++) {
1178 grn_id table_id;
1179 grn_obj *table;
1180
1181 if (data->is_close_opened_object_mode) {
1182 grn_ctx_push_temporary_open_space(ctx);
1183 }
1184
1185 table_id = GRN_RECORD_VALUE_AT(&table_ids, i);
1186 table = grn_ctx_at(ctx, table_id);
1187
1188 command_schema_output_table(ctx, data, table);
1189
1190 if (data->is_close_opened_object_mode) {
1191 grn_ctx_pop_temporary_open_space(ctx);
1192 }
1193 }
1194 grn_ctx_output_map_close(ctx);
1195
1196 GRN_OBJ_FIN(ctx, &table_ids);
1197}
1198
1199static grn_obj *
1200command_schema(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
1201{
1202 grn_schema_data data;
1203
1204 data.is_close_opened_object_mode = (grn_thread_get_limit() == 1);
1205
1206 grn_ctx_output_map_open(ctx, "schema", 6);
1207 command_schema_output_plugins(ctx);
1208 command_schema_output_types(ctx);
1209 command_schema_output_tokenizers(ctx, &data);
1210 command_schema_output_normalizers(ctx, &data);
1211 command_schema_output_token_filters(ctx, &data);
1212 command_schema_output_tables(ctx, &data);
1213 grn_ctx_output_map_close(ctx);
1214
1215 return NULL;
1216}
1217
1218void
1219grn_proc_init_schema(grn_ctx *ctx)
1220{
1221 grn_plugin_command_create(ctx,
1222 "schema", -1,
1223 command_schema,
1224 0,
1225 NULL);
1226}
1227