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 | |
27 | grn_column_flags |
28 | grn_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 | |
75 | static grn_rc |
76 | command_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 | |
110 | static grn_rc |
111 | command_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 | |
169 | static grn_obj * |
170 | command_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 | |
271 | exit : |
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 | |
279 | void |
280 | grn_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 | |
296 | static grn_obj * |
297 | command_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 | |
362 | void |
363 | grn_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 | |
376 | static grn_obj * |
377 | command_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 | |
471 | exit : |
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 | |
478 | void |
479 | grn_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 | |
493 | static void |
494 | output_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 | |
508 | static int |
509 | output_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 | |
559 | static grn_obj * |
560 | command_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 | |
692 | void |
693 | grn_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 | |
705 | static grn_rc |
706 | command_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 | |
754 | static void |
755 | command_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 | |
780 | static void |
781 | command_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 | |
819 | static void |
820 | command_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 | |
915 | static grn_obj * |
916 | command_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 | |
986 | exit : |
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 | |
1005 | void |
1006 | grn_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 | |