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 | |
27 | static grn_table_flags |
28 | command_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 | |
69 | static grn_bool |
70 | grn_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 | |
93 | static grn_bool |
94 | grn_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 | |
141 | break_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 | |
164 | grn_bool |
165 | grn_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 | |
188 | static grn_obj * |
189 | command_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 | |
335 | exit : |
336 | grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS); |
337 | return NULL; |
338 | } |
339 | |
340 | void |
341 | grn_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 | |
359 | static int |
360 | output_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 | |
396 | static grn_obj * |
397 | command_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 = 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 | |
517 | void |
518 | grn_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 | |
530 | static grn_obj * |
531 | command_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 | |
579 | void |
580 | grn_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 | |
593 | static grn_obj * |
594 | command_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 | } |
642 | exit : |
643 | grn_ctx_output_bool(ctx, !rc); |
644 | if (table) { grn_obj_unlink(ctx, table); } |
645 | return NULL; |
646 | } |
647 | |
648 | void |
649 | grn_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 | |
662 | static grn_rc |
663 | command_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 | |
691 | static void |
692 | command_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 | |
734 | static void |
735 | command_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 | |
826 | static grn_obj * |
827 | command_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 | |
885 | exit : |
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 | |
898 | void |
899 | grn_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 | |