From a175314c3e5827eb193872241446f2f8f5c9d33c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 20:07:14 +0200 Subject: Adding upstream version 1:10.5.12. Signed-off-by: Daniel Baumann --- .../mroonga/vendor/groonga/lib/proc/proc_column.c | 1019 ++++++++++++++++++++ 1 file changed, 1019 insertions(+) create mode 100644 storage/mroonga/vendor/groonga/lib/proc/proc_column.c (limited to 'storage/mroonga/vendor/groonga/lib/proc/proc_column.c') diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_column.c b/storage/mroonga/vendor/groonga/lib/proc/proc_column.c new file mode 100644 index 00000000..74d0d7a9 --- /dev/null +++ b/storage/mroonga/vendor/groonga/lib/proc/proc_column.c @@ -0,0 +1,1019 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2009-2016 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA +*/ + +#include "../grn_proc.h" + +#include "../grn_ctx.h" +#include "../grn_db.h" +#include "../grn_str.h" + +#include + +grn_column_flags +grn_proc_column_parse_flags(grn_ctx *ctx, + const char *error_message_tag, + const char *text, + const char *end) +{ + grn_column_flags flags = 0; + while (text < end) { + size_t name_size; + + if (*text == '|' || *text == ' ') { + text += 1; + continue; + } + +#define CHECK_FLAG(name) \ + name_size = strlen(#name); \ + if ((unsigned long) (end - text) >= (unsigned long) name_size && \ + memcmp(text, #name, name_size) == 0) { \ + flags |= GRN_OBJ_ ## name; \ + text += name_size; \ + continue; \ + } + + CHECK_FLAG(COLUMN_SCALAR); + CHECK_FLAG(COLUMN_VECTOR); + CHECK_FLAG(COLUMN_INDEX); + CHECK_FLAG(COMPRESS_ZLIB); + CHECK_FLAG(COMPRESS_LZ4); + CHECK_FLAG(COMPRESS_ZSTD); + CHECK_FLAG(WITH_SECTION); + CHECK_FLAG(WITH_WEIGHT); + CHECK_FLAG(WITH_POSITION); + CHECK_FLAG(RING_BUFFER); + CHECK_FLAG(INDEX_SMALL); + CHECK_FLAG(INDEX_MEDIUM); + +#undef CHECK_FLAG + + ERR(GRN_INVALID_ARGUMENT, + "%s unknown flag: <%.*s>", + error_message_tag, + (int)(end - text), text); + return 0; + } + return flags; +} + +static grn_rc +command_column_create_resolve_source_name(grn_ctx *ctx, + grn_obj *table, + const char *source_name, + int source_name_length, + grn_obj *source_ids) +{ + grn_obj *column; + + column = grn_obj_column(ctx, table, source_name, source_name_length); + if (!column) { + ERR(GRN_INVALID_ARGUMENT, + "[column][create] nonexistent source: <%.*s>", + source_name_length, source_name); + return ctx->rc; + } + + if (column->header.type == GRN_ACCESSOR) { + if (strncmp(source_name, "_key", source_name_length) == 0) { + grn_id source_id = grn_obj_id(ctx, table); + GRN_UINT32_PUT(ctx, source_ids, source_id); + } else { + ERR(GRN_INVALID_ARGUMENT, + "[column][create] pseudo column except <_key> is invalid: <%.*s>", + source_name_length, source_name); + } + } else { + grn_id source_id = grn_obj_id(ctx, column); + GRN_UINT32_PUT(ctx, source_ids, source_id); + } + grn_obj_unlink(ctx, column); + + return ctx->rc; +} + +static grn_rc +command_column_create_resolve_source_names(grn_ctx *ctx, + grn_obj *table, + grn_obj *source_names, + grn_obj *source_ids) +{ + int i, names_length; + int start, source_name_length; + const char *names; + + names = GRN_TEXT_VALUE(source_names); + start = 0; + source_name_length = 0; + names_length = GRN_TEXT_LEN(source_names); + for (i = 0; i < names_length; i++) { + switch (names[i]) { + case ' ' : + if (source_name_length == 0) { + start++; + } + break; + case ',' : + { + grn_rc rc; + const char *source_name = names + start; + rc = command_column_create_resolve_source_name(ctx, + table, + source_name, + source_name_length, + source_ids); + if (rc) { + return rc; + } + start = i + 1; + source_name_length = 0; + } + break; + default : + source_name_length++; + break; + } + } + + if (source_name_length > 0) { + grn_rc rc; + const char *source_name = names + start; + rc = command_column_create_resolve_source_name(ctx, + table, + source_name, + source_name_length, + source_ids); + if (rc) { + return rc; + } + } + + return GRN_SUCCESS; +} + +static grn_obj * +command_column_create(grn_ctx *ctx, int nargs, grn_obj **args, + grn_user_data *user_data) +{ + grn_bool succeeded = GRN_TRUE; + grn_obj *table; + grn_obj *column; + grn_obj *table_raw; + grn_obj *name; + grn_obj *flags_raw; + grn_obj *type_raw; + grn_obj *source_raw; + grn_column_flags flags; + grn_obj *type = NULL; + + table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1); + name = grn_plugin_proc_get_var(ctx, user_data, "name", -1); + flags_raw = grn_plugin_proc_get_var(ctx, user_data, "flags", -1); + type_raw = grn_plugin_proc_get_var(ctx, user_data, "type", -1); + source_raw = grn_plugin_proc_get_var(ctx, user_data, "source", -1); + + table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_raw), GRN_TEXT_LEN(table_raw)); + if (!table) { + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][create] table doesn't exist: <%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw)); + succeeded = GRN_FALSE; + goto exit; + } + + { + const char *rest; + flags = grn_atoi(GRN_TEXT_VALUE(flags_raw), + GRN_BULK_CURR(flags_raw), + &rest); + if (GRN_TEXT_VALUE(flags_raw) == rest) { + flags = grn_proc_column_parse_flags(ctx, + "[column][create][flags]", + GRN_TEXT_VALUE(flags_raw), + GRN_BULK_CURR(flags_raw)); + if (ctx->rc) { + succeeded = GRN_FALSE; + goto exit; + } + } + } + + type = grn_ctx_get(ctx, + GRN_TEXT_VALUE(type_raw), + GRN_TEXT_LEN(type_raw)); + if (!type) { + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][create] type doesn't exist: <%.*s>", + (int)GRN_TEXT_LEN(type_raw), + GRN_TEXT_VALUE(type_raw)); + succeeded = GRN_FALSE; + goto exit; + } + + if (GRN_TEXT_LEN(name) == 0) { + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][create] name is missing"); + succeeded = GRN_FALSE; + goto exit; + } + flags |= GRN_OBJ_PERSISTENT; + + column = grn_column_create(ctx, table, + GRN_TEXT_VALUE(name), + GRN_TEXT_LEN(name), + NULL, flags, type); + if (!column) { + succeeded = GRN_FALSE; + goto exit; + } + + if (GRN_TEXT_LEN(source_raw) > 0) { + grn_rc rc; + grn_obj source_ids; + GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR); + rc = command_column_create_resolve_source_names(ctx, + type, + source_raw, + &source_ids); + if (rc == GRN_SUCCESS && GRN_BULK_VSIZE(&source_ids) > 0) { + grn_obj_set_info(ctx, column, GRN_INFO_SOURCE, &source_ids); + rc = ctx->rc; + } + GRN_OBJ_FIN(ctx, &source_ids); + if (rc != GRN_SUCCESS) { + grn_obj_remove(ctx, column); + succeeded = GRN_FALSE; + goto exit; + } + } + + grn_obj_unlink(ctx, column); + +exit : + grn_ctx_output_bool(ctx, succeeded); + if (table) { grn_obj_unlink(ctx, table); } + if (type) { grn_obj_unlink(ctx, type); } + + return NULL; +} + +void +grn_proc_init_column_create(grn_ctx *ctx) +{ + grn_expr_var vars[5]; + + grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1); + grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1); + grn_plugin_expr_var_init(ctx, &(vars[2]), "flags", -1); + grn_plugin_expr_var_init(ctx, &(vars[3]), "type", -1); + grn_plugin_expr_var_init(ctx, &(vars[4]), "source", -1); + grn_plugin_command_create(ctx, + "column_create", -1, + command_column_create, + 5, + vars); +} + +static grn_obj * +command_column_remove(grn_ctx *ctx, int nargs, grn_obj **args, + grn_user_data *user_data) +{ + grn_obj *table_raw; + grn_obj *name; + grn_obj *table; + grn_obj *column; + char fullname[GRN_TABLE_MAX_KEY_SIZE]; + unsigned int fullname_len; + + table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1); + name = grn_plugin_proc_get_var(ctx, user_data, "name", -1); + + table = grn_ctx_get(ctx, + GRN_TEXT_VALUE(table_raw), + GRN_TEXT_LEN(table_raw)); + + fullname_len = grn_obj_name(ctx, table, fullname, GRN_TABLE_MAX_KEY_SIZE); + if (fullname_len == 0) { + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][remove] table isn't found: <%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw)); + grn_ctx_output_bool(ctx, GRN_FALSE); + return NULL; + } + + fullname[fullname_len] = GRN_DB_DELIMITER; + fullname_len++; + if (fullname_len + GRN_TEXT_LEN(name) > GRN_TABLE_MAX_KEY_SIZE) { + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][remove] column name is too long: <%d> > <%u>: " + "<%.*s>", + (int)GRN_TEXT_LEN(name), + GRN_TABLE_MAX_KEY_SIZE - fullname_len, + (int)GRN_TEXT_LEN(name), + GRN_TEXT_VALUE(name)); + grn_ctx_output_bool(ctx, GRN_FALSE); + return NULL; + } + grn_memcpy(fullname + fullname_len, + GRN_TEXT_VALUE(name), + GRN_TEXT_LEN(name)); + fullname_len += GRN_TEXT_LEN(name); + column = grn_ctx_get(ctx, fullname, fullname_len); + if (!column) { + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][remove] column isn't found: <%.*s%c%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw), + GRN_DB_DELIMITER, + (int)GRN_TEXT_LEN(name), + GRN_TEXT_VALUE(name)); + grn_ctx_output_bool(ctx, GRN_FALSE); + return NULL; + } + + grn_obj_remove(ctx, column); + grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS); + return NULL; +} + +void +grn_proc_init_column_remove(grn_ctx *ctx) +{ + grn_expr_var vars[2]; + + grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1); + grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1); + grn_plugin_command_create(ctx, + "column_remove", -1, + command_column_remove, + 2, + vars); +} + +static grn_obj * +command_column_rename(grn_ctx *ctx, int nargs, grn_obj **args, + grn_user_data *user_data) +{ + grn_rc rc = GRN_SUCCESS; + grn_obj *table_raw; + grn_obj *name; + grn_obj *new_name; + grn_obj *table = NULL; + grn_obj *column = NULL; + + table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1); + name = grn_plugin_proc_get_var(ctx, user_data, "name", -1); + new_name = grn_plugin_proc_get_var(ctx, user_data, "new_name", -1); + + if (GRN_TEXT_LEN(table_raw) == 0) { + rc = GRN_INVALID_ARGUMENT; + GRN_PLUGIN_ERROR(ctx, + rc, + "[column][rename] table name isn't specified"); + goto exit; + } + + table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_raw), GRN_TEXT_LEN(table_raw)); + if (!table) { + rc = GRN_INVALID_ARGUMENT; + GRN_PLUGIN_ERROR(ctx, + rc, + "[column][rename] table isn't found: <%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw)); + goto exit; + } + + if (GRN_TEXT_LEN(name) == 0) { + rc = GRN_INVALID_ARGUMENT; + GRN_PLUGIN_ERROR(ctx, + rc, + "[column][rename] column name isn't specified: <%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw)); + goto exit; + } + + column = grn_obj_column(ctx, table, + GRN_TEXT_VALUE(name), + GRN_TEXT_LEN(name)); + if (!column) { + rc = GRN_INVALID_ARGUMENT; + GRN_PLUGIN_ERROR(ctx, + rc, + "[column][rename] column isn't found: <%.*s%c%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw), + GRN_DB_DELIMITER, + (int)GRN_TEXT_LEN(name), + GRN_TEXT_VALUE(name)); + goto exit; + } + + if (GRN_TEXT_LEN(new_name) == 0) { + rc = GRN_INVALID_ARGUMENT; + GRN_PLUGIN_ERROR(ctx, + rc, + "[column][rename] new column name isn't specified: " + "<%.*s%c%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw), + GRN_DB_DELIMITER, + (int)GRN_TEXT_LEN(name), + GRN_TEXT_VALUE(name)); + goto exit; + } + + rc = grn_column_rename(ctx, column, + GRN_TEXT_VALUE(new_name), + GRN_TEXT_LEN(new_name)); + if (rc != GRN_SUCCESS && ctx->rc == GRN_SUCCESS) { + GRN_PLUGIN_ERROR(ctx, + rc, + "[column][rename] failed to rename: " + "<%.*s%c%.*s> -> <%.*s%c%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw), + GRN_DB_DELIMITER, + (int)GRN_TEXT_LEN(name), + GRN_TEXT_VALUE(name), + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw), + GRN_DB_DELIMITER, + (int)GRN_TEXT_LEN(new_name), + GRN_TEXT_VALUE(new_name)); + goto exit; + } + +exit : + grn_ctx_output_bool(ctx, rc == GRN_SUCCESS); + if (column) { grn_obj_unlink(ctx, column); } + if (table) { grn_obj_unlink(ctx, table); } + return NULL; +} + +void +grn_proc_init_column_rename(grn_ctx *ctx) +{ + grn_expr_var vars[3]; + + grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1); + grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1); + grn_plugin_expr_var_init(ctx, &(vars[2]), "new_name", -1); + grn_plugin_command_create(ctx, + "column_rename", -1, + command_column_rename, + 3, + vars); +} + +static void +output_column_name(grn_ctx *ctx, grn_obj *column) +{ + grn_obj bulk; + int name_len; + char name[GRN_TABLE_MAX_KEY_SIZE]; + + GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY); + name_len = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE); + GRN_TEXT_SET(ctx, &bulk, name, name_len); + + grn_ctx_output_obj(ctx, &bulk, NULL); + GRN_OBJ_FIN(ctx, &bulk); +} + +static int +output_column_info(grn_ctx *ctx, grn_obj *column) +{ + grn_obj o; + grn_id id; + const char *type; + const char *path; + + switch (column->header.type) { + case GRN_COLUMN_FIX_SIZE: + type = "fix"; + break; + case GRN_COLUMN_VAR_SIZE: + type = "var"; + break; + case GRN_COLUMN_INDEX: + type = "index"; + break; + default: + GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid header type %d\n", column->header.type); + return 0; + } + id = grn_obj_id(ctx, column); + path = grn_obj_path(ctx, column); + GRN_TEXT_INIT(&o, 0); + grn_ctx_output_array_open(ctx, "COLUMN", 8); + grn_ctx_output_int64(ctx, id); + output_column_name(ctx, column); + grn_ctx_output_cstr(ctx, path); + grn_ctx_output_cstr(ctx, type); + grn_dump_column_create_flags(ctx, grn_column_get_flags(ctx, column), &o); + grn_ctx_output_obj(ctx, &o, NULL); + grn_proc_output_object_id_name(ctx, column->header.domain); + grn_proc_output_object_id_name(ctx, grn_obj_get_range(ctx, column)); + { + grn_db_obj *obj = (grn_db_obj *)column; + grn_id *s = obj->source; + int i = 0, n = obj->source_size / sizeof(grn_id); + grn_ctx_output_array_open(ctx, "SOURCES", n); + for (i = 0; i < n; i++, s++) { + grn_proc_output_object_id_name(ctx, *s); + } + grn_ctx_output_array_close(ctx); + + } + /* output_obj_source(ctx, (grn_db_obj *)column); */ + grn_ctx_output_array_close(ctx); + GRN_OBJ_FIN(ctx, &o); + return 1; +} + +static grn_obj * +command_column_list(grn_ctx *ctx, int nargs, grn_obj **args, + grn_user_data *user_data) +{ + grn_obj *table_raw; + grn_obj *table; + grn_hash *cols; + grn_obj *col; + int column_list_size = -1; + + table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1); + + table = grn_ctx_get(ctx, + GRN_TEXT_VALUE(table_raw), + GRN_TEXT_LEN(table_raw)); + if (!table) { + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][list] table doesn't exist: <%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw)); + return NULL; + } + + if (!grn_obj_is_table(ctx, table)) { + const char *type_name; + type_name = grn_obj_type_to_string(table->header.type); + grn_obj_unlink(ctx, table); + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][list] not table: <%.*s>: <%s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw), + type_name); + return NULL; + } + + column_list_size = 1; /* [header, (key), (COLUMNS)] */ + if (table->header.type != GRN_TABLE_NO_KEY) { + column_list_size++; + } + cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, + GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY); + if (!cols) { + grn_obj_unlink(ctx, table); + GRN_PLUGIN_ERROR(ctx, + GRN_INVALID_ARGUMENT, + "[column][list] " + "failed to create temporary table to list columns: <%.*s>", + (int)GRN_TEXT_LEN(table_raw), + GRN_TEXT_VALUE(table_raw)); + return NULL; + } + + column_list_size += grn_table_columns(ctx, table, NULL, 0, (grn_obj *)cols); + + grn_ctx_output_array_open(ctx, "COLUMN_LIST", column_list_size); + grn_ctx_output_array_open(ctx, "HEADER", 8); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "id"); + grn_ctx_output_cstr(ctx, "UInt32"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "name"); + grn_ctx_output_cstr(ctx, "ShortText"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "path"); + grn_ctx_output_cstr(ctx, "ShortText"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "type"); + grn_ctx_output_cstr(ctx, "ShortText"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "flags"); + grn_ctx_output_cstr(ctx, "ShortText"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "domain"); + grn_ctx_output_cstr(ctx, "ShortText"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "range"); + grn_ctx_output_cstr(ctx, "ShortText"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_open(ctx, "PROPERTY", 2); + grn_ctx_output_cstr(ctx, "source"); + grn_ctx_output_cstr(ctx, "ShortText"); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_close(ctx); + + if ((col = grn_obj_column(ctx, table, + GRN_COLUMN_NAME_KEY, + GRN_COLUMN_NAME_KEY_LEN))) { + int name_len; + char name_buf[GRN_TABLE_MAX_KEY_SIZE]; + grn_id id; + grn_obj buf; + GRN_TEXT_INIT(&buf, 0); + grn_ctx_output_array_open(ctx, "COLUMN", 8); + id = grn_obj_id(ctx, table); + grn_ctx_output_int64(ctx, id); + grn_ctx_output_cstr(ctx, GRN_COLUMN_NAME_KEY); + grn_ctx_output_cstr(ctx, ""); + grn_ctx_output_cstr(ctx, ""); + grn_dump_column_create_flags(ctx, 0, &buf); + grn_ctx_output_obj(ctx, &buf, NULL); + name_len = grn_obj_name(ctx, table, name_buf, GRN_TABLE_MAX_KEY_SIZE); + grn_ctx_output_str(ctx, name_buf, name_len); + grn_proc_output_object_id_name(ctx, table->header.domain); + grn_ctx_output_array_open(ctx, "SOURCES", 0); + grn_ctx_output_array_close(ctx); + grn_ctx_output_array_close(ctx); + GRN_OBJ_FIN(ctx, &buf); + grn_obj_unlink(ctx, col); + } + { + grn_id *key; + GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, { + if ((col = grn_ctx_at(ctx, *key))) { + output_column_info(ctx, col); + grn_obj_unlink(ctx, col); + } + }); + } + grn_ctx_output_array_close(ctx); + grn_hash_close(ctx, cols); + grn_obj_unlink(ctx, table); + + return NULL; +} + +void +grn_proc_init_column_list(grn_ctx *ctx) +{ + grn_expr_var vars[1]; + + grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1); + grn_plugin_command_create(ctx, + "column_list", -1, + command_column_list, + 1, + vars); +} + +static grn_rc +command_column_copy_resolve_target(grn_ctx *ctx, + const char *label, + grn_obj *table_name, + grn_obj *column_name, + grn_obj **table, + grn_obj **column) +{ + if (GRN_TEXT_LEN(table_name) == 0) { + ERR(GRN_INVALID_ARGUMENT, + "[column][copy] %s table name isn't specified", + label); + return ctx->rc; + } + *table = grn_ctx_get(ctx, + GRN_TEXT_VALUE(table_name), + GRN_TEXT_LEN(table_name)); + if (!*table) { + ERR(GRN_INVALID_ARGUMENT, + "[column][copy] %s table isn't found: <%.*s>", + label, + (int)GRN_TEXT_LEN(table_name), + GRN_TEXT_VALUE(table_name)); + return ctx->rc; + } + + if (GRN_TEXT_LEN(column_name) == 0) { + ERR(GRN_INVALID_ARGUMENT, + "[column][copy] %s column name isn't specified: <%.*s>", + label, + (int)GRN_TEXT_LEN(table_name), + GRN_TEXT_VALUE(table_name)); + return ctx->rc; + } + *column = grn_obj_column(ctx, *table, + GRN_TEXT_VALUE(column_name), + GRN_TEXT_LEN(column_name)); + if (!*column) { + ERR(GRN_INVALID_ARGUMENT, + "[column][copy] %s column isn't found: <%.*s.%.*s>", + label, + (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name), + (int)GRN_TEXT_LEN(column_name), GRN_TEXT_VALUE(column_name)); + return ctx->rc; + } + + return ctx->rc; +} + +static void +command_column_copy_same_table(grn_ctx *ctx, grn_obj *table, + grn_obj *from_column, grn_obj *to_column) +{ + grn_table_cursor *cursor; + grn_id id; + grn_obj value; + + cursor = grn_table_cursor_open(ctx, table, + NULL, 0, + NULL, 0, + 0, -1, 0); + if (!cursor) { + return; + } + + GRN_VOID_INIT(&value); + while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) { + GRN_BULK_REWIND(&value); + grn_obj_get_value(ctx, from_column, id, &value); + grn_obj_set_value(ctx, to_column, id, &value, GRN_OBJ_SET); + } + GRN_OBJ_FIN(ctx, &value); + grn_table_cursor_close(ctx, cursor); +} + +static void +command_column_copy_same_key_type(grn_ctx *ctx, + grn_obj *from_table, + grn_obj *from_column, + grn_obj *to_table, + grn_obj *to_column) +{ + grn_table_cursor *cursor; + grn_id from_id; + grn_obj value; + + cursor = grn_table_cursor_open(ctx, from_table, + NULL, 0, + NULL, 0, + 0, -1, 0); + if (!cursor) { + return; + } + + GRN_VOID_INIT(&value); + while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) { + void *key; + int key_size; + grn_id to_id; + + key_size = grn_table_cursor_get_key(ctx, cursor, &key); + to_id = grn_table_add(ctx, to_table, key, key_size, NULL); + if (to_id == GRN_ID_NIL) { + continue; + } + + GRN_BULK_REWIND(&value); + grn_obj_get_value(ctx, from_column, from_id, &value); + grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET); + } + GRN_OBJ_FIN(ctx, &value); + grn_table_cursor_close(ctx, cursor); +} + +static void +command_column_copy_different(grn_ctx *ctx, + grn_obj *from_table, + grn_obj *from_column, + grn_obj *to_table, + grn_obj *to_column, + grn_obj *from_table_name, + grn_obj *from_column_name, + grn_obj *to_table_name, + grn_obj *to_column_name) +{ + grn_table_cursor *cursor; + grn_id from_id; + grn_obj from_key_buffer; + grn_obj to_key_buffer; + grn_obj value; + + cursor = grn_table_cursor_open(ctx, from_table, + NULL, 0, + NULL, 0, + 0, -1, 0); + if (!cursor) { + return; + } + + if (from_table->header.domain == GRN_DB_SHORT_TEXT) { + GRN_SHORT_TEXT_INIT(&from_key_buffer, 0); + } else { + GRN_VALUE_FIX_SIZE_INIT(&from_key_buffer, 0, from_table->header.domain); + } + if (to_table->header.domain == GRN_DB_SHORT_TEXT) { + GRN_SHORT_TEXT_INIT(&to_key_buffer, 0); + } else { + GRN_VALUE_FIX_SIZE_INIT(&to_key_buffer, 0, to_table->header.domain); + } + GRN_VOID_INIT(&value); + while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) { + void *key; + int key_size; + grn_rc cast_rc; + grn_id to_id; + + GRN_BULK_REWIND(&from_key_buffer); + GRN_BULK_REWIND(&to_key_buffer); + + key_size = grn_table_cursor_get_key(ctx, cursor, &key); + grn_bulk_write(ctx, &from_key_buffer, key, key_size); + cast_rc = grn_obj_cast(ctx, &from_key_buffer, &to_key_buffer, GRN_FALSE); + if (cast_rc != GRN_SUCCESS) { + grn_obj *to_key_type; + grn_obj inspected_key; + grn_obj inspected_to_key_type; + + to_key_type = grn_ctx_at(ctx, to_table->header.domain); + GRN_TEXT_INIT(&inspected_key, 0); + GRN_TEXT_INIT(&inspected_to_key_type, 0); + grn_inspect(ctx, &inspected_key, &from_key_buffer); + grn_inspect(ctx, &inspected_to_key_type, to_key_type); + ERR(cast_rc, + "[column][copy] failed to cast key: <%.*s> -> %.*s: " + "<%.*s.%.*s> -> <%.*s.%.*s>", + (int)GRN_TEXT_LEN(&inspected_key), + GRN_TEXT_VALUE(&inspected_key), + (int)GRN_TEXT_LEN(&inspected_to_key_type), + GRN_TEXT_VALUE(&inspected_to_key_type), + (int)GRN_TEXT_LEN(from_table_name), + GRN_TEXT_VALUE(from_table_name), + (int)GRN_TEXT_LEN(from_column_name), + GRN_TEXT_VALUE(from_column_name), + (int)GRN_TEXT_LEN(to_table_name), + GRN_TEXT_VALUE(to_table_name), + (int)GRN_TEXT_LEN(to_column_name), + GRN_TEXT_VALUE(to_column_name)); + GRN_OBJ_FIN(ctx, &inspected_key); + GRN_OBJ_FIN(ctx, &inspected_to_key_type); + break; + } + to_id = grn_table_add(ctx, to_table, + GRN_BULK_HEAD(&to_key_buffer), + GRN_BULK_VSIZE(&to_key_buffer), + NULL); + if (to_id == GRN_ID_NIL) { + continue; + } + + GRN_BULK_REWIND(&value); + grn_obj_get_value(ctx, from_column, from_id, &value); + grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET); + } + GRN_OBJ_FIN(ctx, &from_key_buffer); + GRN_OBJ_FIN(ctx, &to_key_buffer); + GRN_OBJ_FIN(ctx, &value); + + grn_table_cursor_close(ctx, cursor); +} + +static grn_obj * +command_column_copy(grn_ctx *ctx, int nargs, grn_obj **args, + grn_user_data *user_data) +{ + grn_rc rc = GRN_SUCCESS; + grn_obj *from_table = NULL; + grn_obj *from_column = NULL; + grn_obj *to_table = NULL; + grn_obj *to_column = NULL; + grn_obj *from_table_name; + grn_obj *from_column_name; + grn_obj *to_table_name; + grn_obj *to_column_name; + + from_table_name = grn_plugin_proc_get_var(ctx, user_data, "from_table", -1); + from_column_name = grn_plugin_proc_get_var(ctx, user_data, "from_name", -1); + to_table_name = grn_plugin_proc_get_var(ctx, user_data, "to_table", -1); + to_column_name = grn_plugin_proc_get_var(ctx, user_data, "to_name", -1); + + rc = command_column_copy_resolve_target(ctx, "from", + from_table_name, from_column_name, + &from_table, &from_column); + if (rc != GRN_SUCCESS) { + goto exit; + } + rc = command_column_copy_resolve_target(ctx, "to", + to_table_name, to_column_name, + &to_table, &to_column); + if (rc != GRN_SUCCESS) { + goto exit; + } + + if ((from_table->header.type == GRN_TABLE_NO_KEY || + to_table->header.type == GRN_TABLE_NO_KEY) && + from_table != to_table) { + rc = GRN_OPERATION_NOT_SUPPORTED; + GRN_PLUGIN_ERROR(ctx, + rc, + "[column][copy] copy from/to TABLE_NO_KEY isn't supported: " + "<%.*s%c%.*s> -> <%.*s%c%.*s>", + (int)GRN_TEXT_LEN(from_table_name), + GRN_TEXT_VALUE(from_table_name), + GRN_DB_DELIMITER, + (int)GRN_TEXT_LEN(from_column_name), + GRN_TEXT_VALUE(from_column_name), + (int)GRN_TEXT_LEN(to_table_name), + GRN_TEXT_VALUE(to_table_name), + GRN_DB_DELIMITER, + (int)GRN_TEXT_LEN(to_column_name), + GRN_TEXT_VALUE(to_column_name)); + goto exit; + } + + if (from_table == to_table) { + command_column_copy_same_table(ctx, from_table, from_column, to_column); + } else if (from_table->header.domain == to_table->header.domain) { + command_column_copy_same_key_type(ctx, + from_table, from_column, + to_table, to_column); + } else { + command_column_copy_different(ctx, + from_table, + from_column, + to_table, + to_column, + from_table_name, + from_column_name, + to_table_name, + to_column_name); + } + +exit : + grn_ctx_output_bool(ctx, rc == GRN_SUCCESS); + + if (to_column) { + grn_obj_unlink(ctx, to_column); + } + if (to_table) { + grn_obj_unlink(ctx, to_table); + } + if (from_column) { + grn_obj_unlink(ctx, from_column); + } + if (from_table) { + grn_obj_unlink(ctx, from_table); + } + + return NULL; +} + +void +grn_proc_init_column_copy(grn_ctx *ctx) +{ + grn_expr_var vars[4]; + + grn_plugin_expr_var_init(ctx, &(vars[0]), "from_table", -1); + grn_plugin_expr_var_init(ctx, &(vars[1]), "from_name", -1); + grn_plugin_expr_var_init(ctx, &(vars[2]), "to_table", -1); + grn_plugin_expr_var_init(ctx, &(vars[3]), "to_name", -1); + grn_plugin_command_create(ctx, + "column_copy", -1, + command_column_copy, + 4, + vars); +} -- cgit v1.2.3