Beispiel #1
0
static mrb_value
mrb_grn_table_group_raw(mrb_state *mrb, mrb_value self)
{
  grn_ctx *ctx = (grn_ctx *)mrb->ud;
  grn_obj *table;
  mrb_value mrb_keys;
  grn_table_sort_key *keys;
  int i, n_keys;
  mrb_value mrb_result;
  grn_table_group_result *result;

  table = DATA_PTR(self);
  mrb_get_args(mrb, "oo", &mrb_keys, &mrb_result);

  mrb_keys = mrb_convert_type(mrb, mrb_keys,
                              MRB_TT_ARRAY, "Array", "to_ary");

  n_keys = RARRAY_LEN(mrb_keys);
  keys = GRN_MALLOCN(grn_table_sort_key, n_keys);
  for (i = 0; i < n_keys; i++) {
    memcpy(&(keys[i]),
           DATA_PTR(RARRAY_PTR(mrb_keys)[i]),
           sizeof(grn_table_sort_key));
  }
  result = DATA_PTR(mrb_result);
  grn_table_group(ctx, table, keys, n_keys, result, 1);
  GRN_FREE(keys);
  grn_mrb_ctx_check(mrb);

  return mrb_result;
}
Beispiel #2
0
grn_rc
grn_ts_obj_cursor_open(grn_ctx *ctx, grn_obj *obj, grn_ts_cursor **cursor)
{
  grn_ts_obj_cursor *new_cursor;
  if (!ctx) {
    return GRN_INVALID_ARGUMENT;
  }
  if (!obj || !cursor) {
    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
  }
  switch (obj->header.type) {
    case GRN_CURSOR_TABLE_HASH_KEY:
    case GRN_CURSOR_TABLE_PAT_KEY:
    case GRN_CURSOR_TABLE_DAT_KEY:
    case GRN_CURSOR_TABLE_NO_KEY: {
      break;
    }
    default: {
      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
    }
  }
  new_cursor = GRN_MALLOCN(grn_ts_obj_cursor, 1);
  if (!new_cursor) {
    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
                      "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
                      sizeof(grn_ts_obj_cursor));
  }
  new_cursor->type = GRN_TS_OBJ_CURSOR;
  new_cursor->obj = obj;
  *cursor = (grn_ts_cursor *)new_cursor;
  return GRN_SUCCESS;
}
Beispiel #3
0
grn_obj *
grn_string_open_(grn_ctx *ctx, const char *str, unsigned int str_len,
                 grn_obj *normalizer, int flags, grn_encoding encoding)
{
  grn_string *string;
  grn_obj *obj;
  grn_bool is_normalizer_auto;

  if (!str || !str_len) {
    return NULL;
  }

  is_normalizer_auto = (normalizer == GRN_NORMALIZER_AUTO);
  if (is_normalizer_auto) {
    normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
    if (!normalizer) {
      ERR(GRN_INVALID_ARGUMENT,
          "[string][open] NormalizerAuto normalizer isn't available");
      return NULL;
    }
  }

  string = GRN_MALLOCN(grn_string, 1);
  if (!string) {
    if (is_normalizer_auto) {
      grn_obj_unlink(ctx, normalizer);
    }
    GRN_LOG(ctx, GRN_LOG_ALERT,
            "[string][open] failed to allocate memory");
    return NULL;
  }

  obj = (grn_obj *)string;
  GRN_OBJ_INIT(obj, GRN_STRING, GRN_OBJ_ALLOCATED, GRN_ID_NIL);
  string->original = str;
  string->original_length_in_bytes = str_len;
  string->normalized = NULL;
  string->normalized_length_in_bytes = 0;
  string->n_characters = 0;
  string->checks = NULL;
  string->ctypes = NULL;
  string->encoding = encoding;
  string->flags = flags;

  if (!normalizer) {
    return (grn_obj *)grn_fake_string_open(ctx, string);
  }

  grn_normalizer_normalize(ctx, normalizer, (grn_obj *)string);
  if (ctx->rc) {
    grn_obj_close(ctx, obj);
    obj = NULL;
  }

  if (is_normalizer_auto) {
    grn_obj_unlink(ctx, normalizer);
  }

  return obj;
}
Beispiel #4
0
/*
 * grn_ts_writer_output_body() evaluates expressions and outputs the results.
 */
static grn_rc
grn_ts_writer_output_body(grn_ctx *ctx, grn_ts_writer *writer,
                          const grn_ts_record *in, size_t n_in)
{
  size_t i, j, count = 0;
  writer->bufs = GRN_MALLOCN(grn_ts_buf, writer->n_exprs);
  if (!writer->bufs) {
    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
                      "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE,
                      sizeof(grn_ts_buf), writer->n_exprs);
  }
  for (i = 0; i < writer->n_exprs; i++) {
    grn_ts_buf_init(ctx, &writer->bufs[i]);
  }
  while (count < n_in) {
    size_t batch_size = GRN_TS_BATCH_SIZE;
    if (batch_size > (n_in - count)) {
      batch_size = n_in - count;
    }
    for (i = 0; i < writer->n_exprs; ++i) {
      grn_rc rc = grn_ts_expr_evaluate_to_buf(ctx, writer->exprs[i], in + count,
                                              batch_size, &writer->bufs[i]);
      if (rc != GRN_SUCCESS) {
        return rc;
      }
    }
    for (i = 0; i < batch_size; ++i) {
      GRN_OUTPUT_ARRAY_OPEN("HIT", writer->n_exprs);
      for (j = 0; j < writer->n_exprs; ++j) {
        if (j) {
          GRN_TEXT_PUTC(ctx, ctx->impl->output.buf, ',');
        }
        switch (writer->exprs[j]->data_kind) {
          GRN_TS_WRITER_OUTPUT_BODY_CASE(BOOL, bool);
          GRN_TS_WRITER_OUTPUT_BODY_CASE(INT, int);
          GRN_TS_WRITER_OUTPUT_BODY_CASE(FLOAT, float);
          GRN_TS_WRITER_OUTPUT_BODY_CASE(TIME, time);
          GRN_TS_WRITER_OUTPUT_BODY_CASE(TEXT, text);
          GRN_TS_WRITER_OUTPUT_BODY_CASE(GEO, geo);
          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(BOOL, bool);
          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(INT, int);
          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(FLOAT, float);
          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TIME, time);
          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TEXT, text);
          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(GEO, geo);
          default: {
            break;
          }
        }
      }
      GRN_OUTPUT_ARRAY_CLOSE(); /* HITS. */
    }
    count += batch_size;
  }
  return GRN_SUCCESS;
}
Beispiel #5
0
static mrb_value
indexable_indexes(mrb_state *mrb, mrb_value self)
{
  grn_ctx *ctx = (grn_ctx *)mrb->ud;
  grn_obj *object;
  grn_index_datum index_datum;
  grn_index_datum *index_data;
  int i, n_index_data;
  mrb_value mrb_indexes;

  object = DATA_PTR(self);
  n_index_data = grn_column_get_all_index_data(ctx, object, &index_datum, 1);
  if (n_index_data == 0) {
    return mrb_ary_new(mrb);
  }

  if (n_index_data == 1) {
    index_data = &index_datum;
  } else {
    index_data = GRN_MALLOCN(grn_index_datum, n_index_data);
    n_index_data = grn_column_get_all_index_data(ctx,
                                                 object,
                                                 index_data,
                                                 n_index_data);
  }

  mrb_indexes = mrb_ary_new_capa(mrb, n_index_data);
  for (i = 0; i < n_index_data; i++) {
    grn_mrb_data *data;
    struct RClass *klass;
    mrb_value args[2];

    data = &(ctx->impl->mrb);
    klass = mrb_class_get_under(mrb, data->module, "IndexInfo");
    args[0] = grn_mrb_value_from_grn_obj(mrb, index_data[i].index);
    args[1] = mrb_fixnum_value(index_data[i].section);
    mrb_ary_push(mrb, mrb_indexes, mrb_obj_new(mrb, klass, 2, args));
  }

  if (index_data != &index_datum) {
    GRN_FREE(index_data);
  }

  return mrb_indexes;
}
Beispiel #6
0
static grn_id
grn_plugin_open_mrb(grn_ctx *ctx, const char *filename, size_t filename_size)
{
  grn_ctx *plugins_ctx = &grn_plugins_ctx;
  grn_id id = GRN_ID_NIL;
  grn_plugin **plugin = NULL;

  grn_ctx_impl_mrb_ensure_init(ctx);
  if (ctx->rc != GRN_SUCCESS) {
    return GRN_ID_NIL;
  }

  if (!ctx->impl->mrb.state) {
    ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "mruby support isn't enabled");
    return GRN_ID_NIL;
  }

  id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size,
                    (void **)&plugin, NULL);
  if (!id) {
    return id;
  }

  {
    grn_ctx *ctx = plugins_ctx;
    *plugin = GRN_MALLOCN(grn_plugin, 1);
  }
  if (!*plugin) {
    grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
    return GRN_ID_NIL;
  }

  grn_memcpy((*plugin)->path, filename, filename_size);
  (*plugin)->dl = NULL;
  (*plugin)->init_func = NULL;
  (*plugin)->register_func = NULL;
  (*plugin)->fin_func = NULL;
  (*plugin)->refcount = 1;

  return id;
}
Beispiel #7
0
grn_obj *
grn_msg_open(grn_ctx *ctx, grn_com *com, grn_com_queue *old)
{
  grn_msg *msg = NULL;
  if (old && (msg = (grn_msg *)grn_com_queue_deque(ctx, old))) {
    if (msg->ctx != ctx) {
      ERR(GRN_INVALID_ARGUMENT, "ctx unmatch");
      return NULL;
    }
    GRN_BULK_REWIND(&msg->qe.obj);
  } else if ((msg = GRN_MALLOCN(grn_msg, 1))) {
    GRN_OBJ_INIT(&msg->qe.obj, GRN_MSG, 0, GRN_DB_TEXT);
    msg->qe.obj.header.impl_flags |= GRN_OBJ_ALLOCATED;
    msg->ctx = ctx;
  }
  msg->qe.next = NULL;
  msg->u.peer = com;
  msg->old = old;
  memset(&msg->header, 0, sizeof(grn_com_header));
  return (grn_obj *)msg;
}
Beispiel #8
0
/* grn_ts_writer_build() builds output expresions. */
static grn_rc
grn_ts_writer_build(grn_ctx *ctx, grn_ts_writer *writer, grn_obj *table)
{
  size_t i, n_names = grn_vector_size(ctx, &writer->name_buf);
  if (!n_names) {
    return GRN_SUCCESS;
  }
  writer->names = GRN_MALLOCN(grn_ts_str, n_names);
  if (!writer->names) {
    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
                      "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE,
                      sizeof(grn_ts_str), n_names);
  }
  writer->exprs = GRN_MALLOCN(grn_ts_expr *, n_names);
  if (!writer->exprs) {
    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
                      "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE,
                      sizeof(grn_ts_expr *), n_names);
  }
  for (i = 0; i < n_names; i++) {
    grn_rc rc;
    grn_ts_expr *new_expr;
    const char *name_ptr;
    size_t name_size = grn_vector_get_element(ctx, &writer->name_buf, i,
                                              &name_ptr, NULL, NULL);
    rc = grn_ts_expr_parser_parse(ctx, writer->parser,
                                  (grn_ts_str){ name_ptr, name_size },
                                  &new_expr);
    if (rc != GRN_SUCCESS) {
      return rc;
    }
    writer->names[i].ptr = name_ptr;
    writer->names[i].size = name_size;
    writer->exprs[i] = new_expr;
    writer->n_exprs++;
  }
  return GRN_SUCCESS;
}
Beispiel #9
0
/* grn_ts_writer_open() creates a writer. */
static grn_rc
grn_ts_writer_open(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
                   grn_ts_writer **writer)
{
  grn_rc rc;
  grn_ts_writer *new_writer = GRN_MALLOCN(grn_ts_writer, 1);
  if (!new_writer) {
    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
                      "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
                      sizeof(grn_ts_writer));
  }
  grn_ts_writer_init(ctx, new_writer);
  rc = grn_ts_writer_parse(ctx, new_writer, table, str);
  if (rc == GRN_SUCCESS) {
    rc = grn_ts_writer_build(ctx, new_writer, table);
  }
  if (rc != GRN_SUCCESS) {
    grn_ts_writer_fin(ctx, new_writer);
    GRN_FREE(new_writer);
    return rc;
  }
  *writer = new_writer;
  return GRN_SUCCESS;
}
Beispiel #10
0
/* TODO: Fix memory leak on error */
static mrb_value
mrb_grn_table_sort(mrb_state *mrb, mrb_value self)
{
  grn_ctx *ctx = (grn_ctx *)mrb->ud;
  grn_obj *table;
  grn_obj *result = NULL;
  grn_table_sort_key *keys;
  int i, n_keys;
  int offset = 0;
  int limit = -1;
  mrb_value mrb_keys;
  mrb_value mrb_options = mrb_nil_value();

  table = DATA_PTR(self);
  mrb_get_args(mrb, "o|H", &mrb_keys, &mrb_options);

  mrb_keys = mrb_convert_type(mrb, mrb_keys,
                              MRB_TT_ARRAY, "Array", "to_ary");

  n_keys = RARRAY_LEN(mrb_keys);
  keys = GRN_MALLOCN(grn_table_sort_key, n_keys);
  for (i = 0; i < n_keys; i++) {
    mrb_value mrb_sort_options;
    mrb_value mrb_sort_key;
    mrb_value mrb_sort_order;

    mrb_sort_options = RARRAY_PTR(mrb_keys)[i];
    mrb_sort_key = grn_mrb_options_get_lit(mrb, mrb_sort_options, "key");
    switch (mrb_type(mrb_sort_key)) {
    case MRB_TT_STRING :
      keys[i].key = grn_obj_column(ctx, table,
                                   RSTRING_PTR(mrb_sort_key),
                                   RSTRING_LEN(mrb_sort_key));
      break;
    case MRB_TT_SYMBOL :
      {
        const char *name;
        mrb_int name_length;
        name = mrb_sym2name_len(mrb, mrb_symbol(mrb_sort_key), &name_length);
        keys[i].key = grn_obj_column(ctx, table, name, name_length);
      }
      break;
    default :
      /* TODO: free */
      mrb_raisef(mrb, E_ARGUMENT_ERROR,
                 "sort key must be string or symbol: %S",
                 mrb_sort_key);
      break;
    }

    keys[i].flags = 0;
    mrb_sort_order = grn_mrb_options_get_lit(mrb, mrb_sort_options, "order");
    if (mrb_nil_p(mrb_sort_order) ||
        (mrb_symbol(mrb_sort_order) == mrb_intern_lit(mrb, "ascending"))) {
      keys[i].flags |= GRN_TABLE_SORT_ASC;
    } else {
      keys[i].flags |= GRN_TABLE_SORT_DESC;
    }
  }

  if (!mrb_nil_p(mrb_options)) {
    mrb_value mrb_offset;
    mrb_value mrb_limit;

    mrb_offset = grn_mrb_options_get_lit(mrb, mrb_options, "offset");
    if (!mrb_nil_p(mrb_offset)) {
      offset = mrb_fixnum(mrb_offset);
    }

    mrb_limit = grn_mrb_options_get_lit(mrb, mrb_options, "limit");
    if (!mrb_nil_p(mrb_limit)) {
      limit = mrb_fixnum(mrb_limit);
    }
  }

  result = grn_table_create(ctx, NULL, 0, NULL, GRN_TABLE_NO_KEY,
                            NULL, table);
  grn_table_sort(ctx, table, offset, limit, result, keys, n_keys);
  for (i = 0; i < n_keys; i++) {
    grn_obj_unlink(ctx, keys[i].key);
  }
  GRN_FREE(keys);
  grn_mrb_ctx_check(mrb);

  return grn_mrb_value_from_grn_obj(mrb, result);
}
Beispiel #11
0
grn_rc
grn_ts_expr_open(grn_ctx *ctx, grn_obj *table, grn_ts_expr_node *root,
                 grn_ts_expr **expr)
{
    grn_rc rc;
    grn_ts_expr *new_expr;
    grn_ts_expr_type type;
    if (!ctx) {
        return GRN_INVALID_ARGUMENT;
    }
    if (!table || !grn_ts_obj_is_table(ctx, table) || !root || !expr) {
        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
    }
    switch (root->type) {
    case GRN_TS_EXPR_ID_NODE: {
        type = GRN_TS_EXPR_ID;
        break;
    }
    case GRN_TS_EXPR_SCORE_NODE: {
        type = GRN_TS_EXPR_SCORE;
        break;
    }
    case GRN_TS_EXPR_KEY_NODE:
    case GRN_TS_EXPR_VALUE_NODE: {
        type = GRN_TS_EXPR_VARIABLE;
        break;
    }
    case GRN_TS_EXPR_CONST_NODE: {
        type = GRN_TS_EXPR_CONST;
        break;
    }
    case GRN_TS_EXPR_COLUMN_NODE:
    case GRN_TS_EXPR_OP_NODE:
    case GRN_TS_EXPR_BRIDGE_NODE: {
        type = GRN_TS_EXPR_VARIABLE;
        break;
    }
    default: {
        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
    }
    }
    new_expr = GRN_MALLOCN(grn_ts_expr, 1);
    if (!new_expr) {
        GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
                          "GRN_MALLOCN failed: %" GRN_FMT_SIZE,
                          sizeof(grn_ts_expr));
    }
    rc = grn_ts_obj_increment_ref_count(ctx, table);
    if (rc != GRN_SUCCESS) {
        GRN_FREE(new_expr);
        return rc;
    }
    grn_ts_expr_init(ctx, new_expr);
    new_expr->table = table;
    new_expr->type = type;
    new_expr->data_kind = root->data_kind;
    new_expr->data_type = root->data_type;
    new_expr->root = root;
    *expr = new_expr;
    return GRN_SUCCESS;
}
static void
windows_event_logger_log(grn_ctx *ctx, grn_log_level level,
                         const char *timestamp, const char *title,
                         const char *message, const char *location,
                         void *user_data)
{
    grn_windows_event_logger_data *data = user_data;
    WORD type;
    WORD category = 0;
    DWORD event_id = 0;
    PSID user_sid = NULL;
    WORD n_strings = 1;
    DWORD event_data_size = 0;
    const WCHAR *strings[1];
    LPVOID event_data = NULL;
    const char level_marks[] = " EACewnid-";
    grn_obj formatted_buffer;
    UINT code_page;
    DWORD convert_flags = 0;
    int n_converted_chars;

    switch (level) {
    case GRN_LOG_NONE :
        return;
        break;
    case GRN_LOG_EMERG :
    case GRN_LOG_ALERT :
    case GRN_LOG_CRIT :
    case GRN_LOG_ERROR :
        type = EVENTLOG_ERROR_TYPE;
        break;
    case GRN_LOG_WARNING :
        type = EVENTLOG_WARNING_TYPE;
        break;
    case GRN_LOG_NOTICE :
    case GRN_LOG_INFO :
    case GRN_LOG_DEBUG :
    case GRN_LOG_DUMP :
        type = EVENTLOG_INFORMATION_TYPE;
        break;
    default :
        type = EVENTLOG_ERROR_TYPE;
        break;
    }

    if (data->event_source == INVALID_HANDLE_VALUE) {
        data->event_source = RegisterEventSourceA(NULL, data->event_source_name);
        if (data->event_source == INVALID_HANDLE_VALUE) {
            return;
        }
    }

    GRN_TEXT_INIT(&formatted_buffer, 0);
    if (location && location[0]) {
        grn_text_printf(ctx, &formatted_buffer, "%s|%c|%s %s %s",
                        timestamp, level_marks[level], title, message, location);
    } else {
        grn_text_printf(ctx, &formatted_buffer, "%s|%c|%s %s",
                        timestamp, level_marks[level], title, message);
    }

    code_page = grn_windows_encoding_to_code_page(ctx->encoding);

    n_converted_chars = MultiByteToWideChar(code_page,
                                            convert_flags,
                                            GRN_TEXT_VALUE(&formatted_buffer),
                                            GRN_TEXT_LEN(&formatted_buffer),
                                            NULL,
                                            0);
#define CONVERTED_BUFFER_SIZE 512
    if (n_converted_chars < CONVERTED_BUFFER_SIZE) {
        WCHAR converted_buffer[CONVERTED_BUFFER_SIZE];
        n_converted_chars = MultiByteToWideChar(code_page,
                                                convert_flags,
                                                GRN_TEXT_VALUE(&formatted_buffer),
                                                GRN_TEXT_LEN(&formatted_buffer),
                                                converted_buffer,
                                                CONVERTED_BUFFER_SIZE);
        converted_buffer[n_converted_chars] = L'\0';
        strings[0] = converted_buffer;
        ReportEventW(data->event_source, type, category, event_id, user_sid,
                     n_strings, event_data_size,
                     strings, event_data);
#undef CONVERTED_BUFFER_SIZE
    } else {
        WCHAR *converted;
        converted = GRN_MALLOCN(WCHAR, n_converted_chars);
        n_converted_chars = MultiByteToWideChar(code_page,
                                                convert_flags,
                                                GRN_TEXT_VALUE(&formatted_buffer),
                                                GRN_TEXT_LEN(&formatted_buffer),
                                                converted,
                                                n_converted_chars);
        converted[n_converted_chars] = L'\0';
        strings[0] = converted;
        ReportEventW(data->event_source, type, category, event_id, user_sid,
                     n_strings, event_data_size,
                     strings, event_data);
        GRN_FREE(converted);
    }
    GRN_OBJ_FIN(ctx, &formatted_buffer);
}
Beispiel #13
0
grn_id
grn_plugin_open(grn_ctx *ctx, const char *filename)
{
  grn_ctx *plugins_ctx = &grn_plugins_ctx;
  grn_id id = GRN_ID_NIL;
  grn_dl dl;
  grn_plugin **plugin = NULL;
  size_t filename_size;

  filename_size = GRN_PLUGIN_KEY_SIZE(filename);

  CRITICAL_SECTION_ENTER(grn_plugins_lock);
  if ((id = grn_hash_get(plugins_ctx, grn_plugins, filename, filename_size,
                         (void **)&plugin))) {
    (*plugin)->refcount++;
    goto exit;
  }

#ifdef GRN_WITH_MRUBY
  {
    const char *mrb_suffix;
    mrb_suffix = grn_plugin_get_ruby_suffix();
    if (filename_size > strlen(mrb_suffix) &&
      strcmp(filename + (strlen(filename) - strlen(mrb_suffix)),
             mrb_suffix) == 0) {
      id = grn_plugin_open_mrb(ctx, filename, filename_size);
      goto exit;
    }
  }
#endif /* GRN_WITH_MRUBY */

  if ((dl = grn_dl_open(filename))) {
    if ((id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size,
                           (void **)&plugin, NULL))) {
      {
        grn_ctx *ctx = plugins_ctx;
        *plugin = GRN_MALLOCN(grn_plugin, 1);
      }
      if (*plugin) {
        grn_memcpy((*plugin)->path, filename, filename_size);
        if (grn_plugin_initialize(ctx, *plugin, dl, id, filename)) {
          {
            grn_ctx *ctx = plugins_ctx;
            GRN_FREE(*plugin);
          }
          *plugin = NULL;
        }
      }
      if (!*plugin) {
        grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
        if (grn_dl_close(dl)) {
          /* Now, __FILE__ set in plugin is invalid. */
          ctx->errline = 0;
          ctx->errfile = NULL;
        } else {
          const char *label;
          label = grn_dl_close_error_label();
          SERR("%s", label);
        }
        id = GRN_ID_NIL;
      } else {
        (*plugin)->refcount = 1;
      }
    } else {
      if (!grn_dl_close(dl)) {
        const char *label;
        label = grn_dl_close_error_label();
        SERR("%s", label);
      }
    }
  } else {
    const char *label;
    label = grn_dl_open_error_label();
    SERR("%s", label);
  }

exit:
  CRITICAL_SECTION_LEAVE(grn_plugins_lock);

  return id;
}