Example #1
0
grn_obj *
rb_grn_vector_from_ruby_object (VALUE object, grn_ctx *context, grn_obj *vector)
{
    VALUE *values;
    grn_obj value;
    int i, n;

    if (vector)
	GRN_OBJ_INIT(vector, GRN_VECTOR, 0, GRN_ID_NIL);
    else
	vector = grn_obj_open(context, GRN_VECTOR, 0, 0);

    if (NIL_P(object))
	return vector;

    GRN_VOID_INIT(&value);
    n = RARRAY_LEN(object);
    values = RARRAY_PTR(object);
    for (i = 0; i < n; i++) {
	grn_obj *_value = &value;
	RVAL2GRNOBJ(values[i], context, &_value);
	grn_vector_add_element(context, vector,
			       GRN_BULK_HEAD(&value),
			       GRN_BULK_VSIZE(&value),
			       0,
			       value.header.domain);
    }
    GRN_OBJ_FIN(context, &value);

    return vector;
}
Example #2
0
static void
rb_grn_add_vector_element (VALUE rb_element, grn_ctx *context, grn_obj *vector,
                           grn_obj *value_buffer)
{
    unsigned int weight = 0;
    if (RVAL2CBOOL(rb_obj_is_kind_of(rb_element, rb_cHash))) {
        VALUE rb_value;
        VALUE rb_weight;
        ID id_value;
        ID id_weight;
        CONST_ID(id_value, "value");
        CONST_ID(id_weight, "weight");
        rb_value = rb_hash_aref(rb_element, ID2SYM(id_value));
        rb_weight = rb_hash_aref(rb_element, ID2SYM(id_weight));
        RVAL2GRNOBJ(rb_value, context, &value_buffer);
        if (!NIL_P(rb_weight)) {
            weight = NUM2UINT(rb_weight);
        }
    } else {
        RVAL2GRNOBJ(rb_element, context, &value_buffer);
    }
    grn_vector_add_element(context, vector,
                           GRN_BULK_HEAD(value_buffer),
                           GRN_BULK_VSIZE(value_buffer),
                           weight,
                           value_buffer->header.domain);
}
static int
hash_element_to_vector_element(VALUE key, VALUE value, VALUE user_data)
{
    HashElementToVectorElementData *data =
        (HashElementToVectorElementData *)user_data;
    unsigned int weight;

    weight = NUM2UINT(value);

    if (data->vector->header.type == GRN_UVECTOR) {
        grn_id id = RVAL2GRNID(key, data->context, data->range, data->self);
        grn_uvector_add_element(data->context, data->vector, id, weight);
    } else {
        GRN_BULK_REWIND(data->element_value);
        RVAL2GRNBULK(key, data->context, data->element_value);

        grn_vector_add_element(data->context, data->vector,
                               GRN_BULK_HEAD(data->element_value),
                               GRN_BULK_VSIZE(data->element_value),
                               weight,
                               data->element_value->header.domain);
    }

    return ST_CONTINUE;
}
Example #4
0
void
grn_output_array_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
                      const char *name, int nelements)
{
  put_delimiter(ctx, outbuf, output_type);
  switch (output_type) {
  case GRN_CONTENT_JSON:
    GRN_TEXT_PUTC(ctx, outbuf, '[');
    break;
  case GRN_CONTENT_XML:
    GRN_TEXT_PUTC(ctx, outbuf, '<');
    GRN_TEXT_PUTS(ctx, outbuf, name);
    GRN_TEXT_PUTC(ctx, outbuf, '>');
    grn_vector_add_element(ctx, &ctx->impl->names, name, strlen(name), 0, GRN_DB_SHORT_TEXT);
    break;
  case GRN_CONTENT_TSV:
    if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "[\t"); }
    break;
  case GRN_CONTENT_MSGPACK :
#ifdef HAVE_MESSAGE_PACK
    if (nelements < 0) {
      GRN_LOG(ctx, GRN_LOG_DEBUG,
              "grn_output_array_open nelements (%d) for <%s>",
              nelements,
              name);
    }
    msgpack_pack_array(&ctx->impl->msgpacker, nelements);
#endif
    break;
  case GRN_CONTENT_NONE:
    break;
  }
  INCR_DEPTH(0);
}
Example #5
0
static grn_obj *
snippet_exec(grn_ctx *ctx, grn_obj *snip, grn_obj *text,
             grn_user_data *user_data,
             const char *prefix, int prefix_length,
             const char *suffix, int suffix_length)
{
  grn_rc rc;
  unsigned int i, n_results, max_tagged_length;
  grn_obj snippet_buffer;
  grn_obj *snippets;

  if (GRN_TEXT_LEN(text) == 0) {
    return NULL;
  }

  rc = grn_snip_exec(ctx, snip,
                     GRN_TEXT_VALUE(text), GRN_TEXT_LEN(text),
                     &n_results, &max_tagged_length);
  if (rc != GRN_SUCCESS) {
    return NULL;
  }

  if (n_results == 0) {
    return grn_plugin_proc_alloc(ctx, user_data, GRN_DB_VOID, 0);
  }

  snippets = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_SHORT_TEXT, GRN_OBJ_VECTOR);
  if (!snippets) {
    return NULL;
  }

  GRN_TEXT_INIT(&snippet_buffer, 0);
  grn_bulk_space(ctx, &snippet_buffer,
                 prefix_length + max_tagged_length + suffix_length);
  for (i = 0; i < n_results; i++) {
    unsigned int snippet_length;

    GRN_BULK_REWIND(&snippet_buffer);
    if (prefix_length) {
      GRN_TEXT_PUT(ctx, &snippet_buffer, prefix, prefix_length);
    }
    rc = grn_snip_get_result(ctx, snip, i,
                             GRN_TEXT_VALUE(&snippet_buffer) + prefix_length,
                             &snippet_length);
    if (rc == GRN_SUCCESS) {
      grn_strncat(GRN_TEXT_VALUE(&snippet_buffer),
                  GRN_BULK_WSIZE(&snippet_buffer),
                  suffix,
                  suffix_length);
      grn_vector_add_element(ctx, snippets,
                             GRN_TEXT_VALUE(&snippet_buffer),
                             prefix_length + snippet_length + suffix_length,
                             0, GRN_DB_SHORT_TEXT);
    }
  }
  GRN_OBJ_FIN(ctx, &snippet_buffer);

  return snippets;
}
Example #6
0
void
test_vector_column(gconstpointer data)
{
  const gchar *expected;
  grn_id id, type_id;
  grn_obj vector;
  grn_obj *elements;
  grn_obj *table, *column;
  const gchar *type_name;
  type_name = gcut_data_get_string(data, "type_name");
  type_id = grn_obj_id(context, get_object(type_name));

  table = table_create("Table", GRN_OBJ_TABLE_NO_KEY, NULL, NULL);
  grn_test_assert_context(context);
  column = column_create("Table", "Column", GRN_OBJ_COLUMN_VECTOR,
                         type_name, NULL);
  grn_test_assert_context(context);
  id = grn_table_add(context, table, NULL, 0, NULL);
  grn_test_assert_context(context);
  cut_assert_equal_int(1, id);
  elements = construct_elements(data);

  GRN_TEXT_INIT(&vector, GRN_OBJ_VECTOR);
  grn_vector_add_element(context, &vector,
                         GRN_TEXT_VALUE(&elements[0]),
                         GRN_TEXT_LEN(&elements[0]), 0, type_id);
  grn_vector_add_element(context, &vector,
                         GRN_TEXT_VALUE(&elements[1]),
                         GRN_TEXT_LEN(&elements[1]), 0, type_id);
  grn_vector_add_element(context, &vector,
                         GRN_TEXT_VALUE(&elements[2]),
                         GRN_TEXT_LEN(&elements[2]), 0, type_id);
  grn_obj_set_value(context, column, id, &vector, GRN_OBJ_SET);

  expected = cut_take_printf("table_create Table TABLE_NO_KEY\n"
                             "column_create Table Column COLUMN_VECTOR %s\n"
                             "load --table Table\n"
                             "[\n"
                             "[\"_id\",\"Column\"],\n"
                             "[1,%s]\n"
                             "]",
                             type_name,
                             gcut_data_get_string(data, "expected"));
  cut_assert_equal_string(expected, send_command("dump"));
  GRN_OBJ_FIN(context, &vector);
}
Example #7
0
/* grn_ts_writer_expand() expands a wildcard. */
static grn_rc
grn_ts_writer_expand(grn_ctx *ctx, grn_ts_writer *writer,
                     grn_obj *table, grn_ts_str str)
{
  grn_rc rc = GRN_SUCCESS;
  grn_hash_cursor *cursor;
  grn_hash *hash = grn_hash_create(ctx, NULL, sizeof(grn_ts_id), 0,
                                   GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
  if (!hash) {
    return GRN_INVALID_ARGUMENT;
  }
  grn_table_columns(ctx, table, str.ptr, str.size - 1, (grn_obj *)hash);
  if (ctx->rc != GRN_SUCCESS) {
    return ctx->rc;
  }
  cursor = grn_hash_cursor_open(ctx, hash, NULL, 0, NULL, 0, 0, -1, 0);
  if (!cursor) {
    rc = GRN_INVALID_ARGUMENT;
  } else {
    while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
      char name_buf[GRN_TABLE_MAX_KEY_SIZE];
      size_t name_size;
      grn_obj *column;
      grn_ts_id *column_id;
      if (!grn_hash_cursor_get_key(ctx, cursor, (void **)&column_id)) {
        rc = GRN_INVALID_ARGUMENT;
        break;
      }
      column = grn_ctx_at(ctx, *column_id);
      if (!column) {
        rc = GRN_INVALID_ARGUMENT;
        break;
      }
      name_size = grn_column_name(ctx, column, name_buf, sizeof(name_buf));
      grn_obj_unlink(ctx, column);
      rc = grn_vector_add_element(ctx, &writer->name_buf,
                                  name_buf, name_size, 0, GRN_DB_TEXT);
      if (rc != GRN_SUCCESS) {
        break;
      }
    }
    grn_hash_cursor_close(ctx, cursor);
  }
  grn_hash_close(ctx, hash);
  return rc;
}
Example #8
0
static void
add_weight_vector(grn_ctx *ctx,
                  grn_obj *column,
                  grn_obj *value,
                  grn_obj *vector)
{
  unsigned int i, n;
  grn_obj weight_buffer;

  n = GRN_UINT32_VALUE(value);
  GRN_UINT32_INIT(&weight_buffer, 0);
  for (i = 0; i < n; i += 2) {
    grn_rc rc;
    grn_obj *key, *weight;

    key = value + 1 + i;
    weight = key + 1;

    GRN_BULK_REWIND(&weight_buffer);
    rc = grn_obj_cast(ctx, weight, &weight_buffer, GRN_TRUE);
    if (rc != GRN_SUCCESS) {
      grn_obj *range;
      range = grn_ctx_at(ctx, weight_buffer.header.domain);
      ERR_CAST(column, range, weight);
      grn_obj_unlink(ctx, range);
      break;
    }
    grn_vector_add_element(ctx,
                           vector,
                           GRN_BULK_HEAD(key),
                           GRN_BULK_VSIZE(key),
                           GRN_UINT32_VALUE(&weight_buffer),
                           key->header.domain);
  }
  GRN_OBJ_FIN(ctx, &weight_buffer);
}
Example #9
0
/* grn_ts_writer_parse() parses output expressions. */
static grn_rc
grn_ts_writer_parse(grn_ctx *ctx, grn_ts_writer *writer,
                    grn_obj *table, grn_ts_str str)
{
  grn_rc rc;
  grn_ts_str rest = str;
  rc = grn_ts_expr_parser_open(ctx, table, &writer->parser);
  for ( ; ; ) {
    grn_ts_str first = { NULL, 0 };
    rc = grn_ts_expr_parser_split(ctx, writer->parser, rest, &first, &rest);
    if (rc != GRN_SUCCESS) {
      return (rc == GRN_END_OF_DATA) ? GRN_SUCCESS : rc;
    }
    if ((first.ptr[first.size - 1] == '*') &&
        grn_ts_str_is_name_prefix((grn_ts_str){ first.ptr, first.size - 1 })) {
      rc = grn_ts_writer_expand(ctx, writer, table, first);
      if (rc != GRN_SUCCESS) {
        return rc;
      }
    } else if (grn_ts_str_is_key_name(first) &&
               !grn_ts_table_has_key(ctx, table)) {
      /*
       * Skip _key if the table has no _key, because the default output_columns
       * option contains _key.
       */
      GRN_TS_DEBUG("skip \"_key\" because the table has no _key");
    } else {
      rc = grn_vector_add_element(ctx, &writer->name_buf,
                                  first.ptr, first.size, 0, GRN_DB_TEXT);
      if (rc != GRN_SUCCESS) {
        return rc;
      }
    }
  }
  return GRN_SUCCESS;
}
/*
 * It updates a value of variable size column value for the record
 * that ID is _id_.
 *
 * Weight vector column is a special variable size column. This
 * description describes only weight vector column. Other variable
 * size column works what you think.
 *
 * @example Use weight vector as matrix search result weight
 *    Groonga::Schema.define do |schema|
 *      schema.create_table("Products",
 *                          :type => :patricia_trie,
 *                          :key_type => "ShortText") do |table|
 *        # This is weight vector.
 *        # ":with_weight => true" is important for matrix search result weight.
 *        table.short_text("tags",
 *                         :type => :vector,
 *                         :with_weight => true)
 *      end
 *
 *      schema.create_table("Tags",
 *                          :type => :hash,
 *                          :key_type => "ShortText") do |table|
 *        # This is inverted index. It also needs ":with_weight => true".
 *        table.index("Products.tags", :with_weight => true)
 *      end
 *    end
 *
 *    products = Groonga["Products"]
 *    groonga = products.add("Groonga")
 *    groonga.tags = [
 *      {
 *        :value  => "groonga",
 *        :weight => 100,
 *      },
 *    ]
 *    rroonga = products.add("Rroonga")
 *    rroonga.tags = [
 *      {
 *        :value  => "ruby",
 *        :weight => 100,
 *      },
 *      {
 *        :value  => "groonga",
 *        :weight => 10,
 *      },
 *    ]
 *
 *    result = products.select do |record|
 *      # Search by "groonga"
 *      record.match("groonga") do |match_target|
 *        match_target.tags
 *      end
 *    end
 *
 *    result.each do |record|
 *      p [record.key.key, record.score]
 *    end
 *    # Matches all records with weight.
 *    # => ["Groonga", 101]
 *    #    ["Rroonga", 11]
 *
 *    # Increases score for "ruby" 10 times
 *    products.select(# The previous search result. Required.
 *                    :result => result,
 *                    # It just adds score to existing records in the result. Required.
 *                    :operator => Groonga::Operator::ADJUST) do |record|
 *      record.match("ruby") do |target|
 *        target.tags * 10 # 10 times
 *      end
 *    end
 *
 *    result.each do |record|
 *      p [record.key.key, record.score]
 *    end
 *    # Weight is used for increasing score.
 *    # => ["Groonga", 101]  <- Not changed.
 *    #    ["Rroonga", 1021] <- 1021 (= 101 * 10 + 1) increased.
 *
 * @overload []=(id, elements)
 *   This description is for weight vector column.
 *
 *   @param [Integer, Record] id The record ID.
 *   @param [Array<Hash<Symbol, String>>] elements An array of values
 *     for weight vector.
 *     Each value is a Hash like the following form:
 *
 *     <pre>
 *     {
 *       :value  => [KEY],
 *       :weight => [WEIGHT],
 *     }
 *     </pre>
 *
 *     @[KEY]@ must be the same type of the key of the table that is
 *     specified as range on creating the weight vector.
 *
 *     @[WEIGHT]@ must be an positive integer. Note that search
 *     becomes @weight + 1@. It means that You want to get 10 as
 *     score, you should set 9 as weight.
 *
 * @overload []=(id, value)
 *   This description is for variable size columns except weight
 *   vector column.
 *
 *   @param [Integer, Record] id The record ID.
 *   @param [::Object] value A new value.
 *   @see Groonga::Object#[]=
 *
 * @since 4.0.1
 */
static VALUE
rb_grn_variable_size_column_array_set (VALUE self, VALUE rb_id, VALUE rb_value)
{
    grn_ctx *context = NULL;
    grn_obj *column, *range;
    grn_rc rc;
    grn_id id;
    grn_obj *value, *element_value;
    int flags = GRN_OBJ_SET;

    rb_grn_variable_size_column_deconstruct(SELF(self), &column, &context,
                                            NULL, NULL, &value, &element_value,
                                            NULL, &range);

    if (!(column->header.flags & GRN_OBJ_WITH_WEIGHT)) {
        VALUE args[2];
        args[0] = rb_id;
        args[1] = rb_value;
        return rb_call_super(2, args);
    }

    id = RVAL2GRNID(rb_id, context, range, self);

    grn_obj_reinit(context, value,
                   value->header.domain,
                   value->header.flags | GRN_OBJ_VECTOR);
    value->header.flags |= GRN_OBJ_WITH_WEIGHT;
    if (RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cArray))) {
        int i, n;
        n = RARRAY_LEN(rb_value);
        for (i = 0; i < n; i++) {
            unsigned int weight = 0;
            VALUE rb_element_value, rb_weight;

            rb_grn_scan_options(RARRAY_PTR(rb_value)[i],
                                "value", &rb_element_value,
                                "weight", &rb_weight,
                                NULL);

            if (!NIL_P(rb_weight)) {
                weight = NUM2UINT(rb_weight);
            }

            if (value->header.type == GRN_UVECTOR) {
                grn_id id = RVAL2GRNID(rb_element_value, context, range, self);
                grn_uvector_add_element(context, value, id, weight);
            } else {
                GRN_BULK_REWIND(element_value);
                if (!NIL_P(rb_element_value)) {
                    RVAL2GRNBULK(rb_element_value, context, element_value);
                }

                grn_vector_add_element(context, value,
                                       GRN_BULK_HEAD(element_value),
                                       GRN_BULK_VSIZE(element_value),
                                       weight,
                                       element_value->header.domain);
            }
        }
    } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cHash))) {
        HashElementToVectorElementData data;
        data.self = self;
        data.context = context;
        data.vector = value;
        data.element_value = element_value;
        data.range = range;
        rb_hash_foreach(rb_value, hash_element_to_vector_element, (VALUE)&data);
    } else {
        rb_raise(rb_eArgError,
                 "<%s>: "
                 "weight vector value must be an array of index value or "
                 "a hash that key is vector value and value is vector weight: "
                 "<%s>",
                 rb_grn_inspect(self),
                 rb_grn_inspect(rb_value));
    }

    rc = grn_obj_set_value(context, column, id, value, flags);
    rb_grn_context_check(context, self);
    rb_grn_rc_check(rc, self);

    return rb_value;
}
Example #11
0
static void
brace_close(grn_ctx *ctx, grn_loader *loader)
{
  grn_id id = GRN_ID_NIL;
  grn_obj *value, *value_begin, *value_end;
  grn_obj *id_value = NULL, *key_value = NULL;
  uint32_t begin;

  GRN_UINT32_POP(&loader->level, begin);
  value_begin = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
  value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
  GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACE);
  GRN_UINT32_SET(ctx, value_begin, loader->values_size - begin - 1);
  value_begin++;
  if (GRN_BULK_VSIZE(&loader->level) > sizeof(uint32_t) * loader->emit_level) {
    return;
  }
  if (!loader->table) {
    goto exit;
  }

  /* Scan values to find _id or _key. */
  for (value = value_begin; value + 1 < value_end;
       value = values_next(ctx, value)) {
    const char *name = GRN_TEXT_VALUE(value);
    unsigned int name_size = GRN_TEXT_LEN(value);
    if (value->header.domain != GRN_DB_TEXT) {
      grn_obj buffer;
      GRN_TEXT_INIT(&buffer, 0);
      grn_inspect(ctx, &buffer, value);
      GRN_LOG(ctx, GRN_LOG_ERROR,
              "column name must be string: <%.*s>",
              (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
      GRN_OBJ_FIN(ctx, &buffer);
      goto exit;
    }
    value++;
    if (name_equal(name, name_size, GRN_COLUMN_NAME_ID)) {
      if (id_value || key_value) {
        if (loader->table->header.type == GRN_TABLE_NO_KEY) {
          GRN_LOG(ctx, GRN_LOG_ERROR, "duplicated '_id' column");
          goto exit;
        } else {
          GRN_LOG(ctx, GRN_LOG_ERROR,
                  "duplicated key columns: %s and %s",
                  id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
                  GRN_COLUMN_NAME_ID);
          goto exit;
        }
      }
      id_value = value;
    } else if (name_equal(name, name_size, GRN_COLUMN_NAME_KEY)) {
      if (id_value || key_value) {
        GRN_LOG(ctx, GRN_LOG_ERROR,
                "duplicated key columns: %s and %s",
                id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
                GRN_COLUMN_NAME_KEY);
        goto exit;
      }
      key_value = value;
    }
  }

  switch (loader->table->header.type) {
  case GRN_TABLE_HASH_KEY :
  case GRN_TABLE_PAT_KEY :
  case GRN_TABLE_DAT_KEY :
    /* The target table requires _id or _key. */
    if (!id_value && !key_value) {
      GRN_LOG(ctx, GRN_LOG_ERROR, "neither _key nor _id is assigned");
      goto exit;
    }
    break;
  default :
    /* The target table does not have _key. */
    if (key_value) {
      GRN_LOG(ctx, GRN_LOG_ERROR, "nonexistent key value");
      goto exit;
    }
    break;
  }

  if (id_value) {
    id = parse_id_value(ctx, id_value);
    if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
      if (ctx->rc == GRN_SUCCESS) {
        id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
      }
    }
  } else if (key_value) {
    id = loader_add(ctx, key_value);
  } else {
    id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
  }
  if (id == GRN_ID_NIL) {
    /* Target record is not available. */
    goto exit;
  }

  for (value = value_begin; value + 1 < value_end;
       value = values_next(ctx, value)) {
    grn_obj *col;
    const char *name = GRN_TEXT_VALUE(value);
    unsigned int name_size = GRN_TEXT_LEN(value);
    value++;
    if (value == id_value || value == key_value) {
      /* Skip _id and _key, because it's already used to get id. */
      continue;
    }
    col = grn_obj_column(ctx, loader->table, name, name_size);
    if (!col) {
      GRN_LOG(ctx, GRN_LOG_ERROR, "invalid column('%.*s')",
              (int)name_size, name);
      /* Automatic column creation is disabled. */
      /*
      if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
        grn_obj *v = value + 1;
        col = grn_column_create(ctx, loader->table, name, name_size,
                                NULL, GRN_OBJ_PERSISTENT|GRN_OBJ_COLUMN_VECTOR,
                                grn_ctx_at(ctx, v->header.domain));
      } else {
        col = grn_column_create(ctx, loader->table, name, name_size,
                                NULL, GRN_OBJ_PERSISTENT,
                                grn_ctx_at(ctx, value->header.domain));
      }
      */
    } else {
      if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
        set_vector(ctx, col, id, value);
      } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
        set_weight_vector(ctx, col, id, value);
      } else {
        grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
      }
      if (ctx->rc != GRN_SUCCESS) {
        grn_loader_save_error(ctx, loader);
        report_set_column_value_failure(ctx, key_value,
                                        name, name_size, value);
        loader->n_column_errors++;
        ERRCLR(ctx);
      }
      grn_obj_unlink(ctx, col);
    }
  }
  if (loader->each) {
    value = grn_expr_get_var_by_offset(ctx, loader->each, 0);
    GRN_RECORD_SET(ctx, value, id);
    grn_expr_exec(ctx, loader->each, 0);
  }
  loader->nrecords++;
exit:
  if (ctx->rc != GRN_SUCCESS) {
    loader->n_record_errors++;
  }
  if (loader->output_ids) {
    GRN_UINT32_PUT(ctx, &(loader->ids), id);
  }
  if (loader->output_errors) {
    GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
    grn_vector_add_element(ctx,
                           &(loader->error_messages),
                           ctx->errbuf,
                           strlen(ctx->errbuf),
                           0,
                           GRN_DB_TEXT);
  }
  loader->values_size = begin;
  ERRCLR(ctx);
}
Example #12
0
static void
bracket_close(grn_ctx *ctx, grn_loader *loader)
{
  grn_id id = GRN_ID_NIL;
  grn_obj *value, *value_end, *id_value = NULL, *key_value = NULL;
  grn_obj *col, **cols; /* Columns except _id and _key. */
  uint32_t i, begin;
  uint32_t ncols;   /* Number of columns except _id and _key. */
  uint32_t nvalues; /* Number of values in brackets. */
  uint32_t depth;
  grn_bool is_record_load = GRN_FALSE;

  cols = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
  ncols = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
  GRN_UINT32_POP(&loader->level, begin);
  value = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
  value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
  GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET);
  GRN_UINT32_SET(ctx, value, loader->values_size - begin - 1);
  value++;
  depth = GRN_BULK_VSIZE(&loader->level);
  if (depth > sizeof(uint32_t) * loader->emit_level) {
    return;
  }
  if (depth == 0 || !loader->table ||
      loader->columns_status == GRN_LOADER_COLUMNS_BROKEN) {
    goto exit;
  }
  nvalues = values_len(ctx, value, value_end);

  if (loader->columns_status == GRN_LOADER_COLUMNS_UNSET) {
    /*
     * Target columns and _id or _key are not specified yet and values are
     * handled as column names and "_id" or "_key".
     */
    for (i = 0; i < nvalues; i++) {
      const char *col_name;
      unsigned int col_name_size;
      if (value->header.domain != GRN_DB_TEXT) {
        grn_obj buffer;
        GRN_TEXT_INIT(&buffer, 0);
        grn_inspect(ctx, &buffer, value);
        ERR(GRN_INVALID_ARGUMENT,
            "column name must be string: <%.*s>",
            (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
        grn_loader_save_error(ctx, loader);
        GRN_OBJ_FIN(ctx, &buffer);
        loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
        goto exit;
      }
      col_name = GRN_TEXT_VALUE(value);
      col_name_size = GRN_TEXT_LEN(value);
      col = grn_obj_column(ctx, loader->table, col_name, col_name_size);
      if (!col) {
        ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s>",
            col_name_size, col_name);
        grn_loader_save_error(ctx, loader);
        loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
        goto exit;
      }
      if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_ID)) {
        grn_obj_unlink(ctx, col);
        if (loader->id_offset != -1 || loader->key_offset != -1) {
          /* _id and _key must not appear more than once. */
          if (loader->id_offset != -1) {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_ID, i,
                GRN_COLUMN_NAME_ID, loader->id_offset);
          } else {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_ID, i,
                GRN_COLUMN_NAME_KEY, loader->key_offset);
          }
          grn_loader_save_error(ctx, loader);
          loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
          goto exit;
        }
        loader->id_offset = i;
      } else if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_KEY)) {
        grn_obj_unlink(ctx, col);
        if (loader->id_offset != -1 || loader->key_offset != -1) {
          /* _id and _key must not appear more than once. */
          if (loader->id_offset != -1) {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_KEY, i,
                GRN_COLUMN_NAME_ID, loader->id_offset);
          } else {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_KEY, i,
                GRN_COLUMN_NAME_KEY, loader->key_offset);
          }
          grn_loader_save_error(ctx, loader);
          loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
          goto exit;
        }
        loader->key_offset = i;
      } else {
        GRN_PTR_PUT(ctx, &loader->columns, col);
      }
      value++;
    }
    switch (loader->table->header.type) {
    case GRN_TABLE_HASH_KEY :
    case GRN_TABLE_PAT_KEY :
    case GRN_TABLE_DAT_KEY :
      if (loader->id_offset == -1 && loader->key_offset == -1) {
        ERR(GRN_INVALID_ARGUMENT, "missing id or key column");
        grn_loader_save_error(ctx, loader);
        loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
        goto exit;
      }
      break;
    }
    loader->columns_status = GRN_LOADER_COLUMNS_SET;
    goto exit;
  }

  is_record_load = GRN_TRUE;

  /* Target columns and _id or _key are already specified. */
  if (!nvalues) {
    /*
     * Accept empty arrays because a dump command may output a load command
     * which contains empty arrays for a table with deleted records.
     */
    id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
  } else {
    uint32_t expected_nvalues = ncols;
    if (loader->id_offset != -1 || loader->key_offset != -1) {
      expected_nvalues++;
    }
    if (nvalues != expected_nvalues) {
      ERR(GRN_INVALID_ARGUMENT,
          "unexpected #values: expected:%u, actual:%u",
          expected_nvalues, nvalues);
      grn_loader_save_error(ctx, loader);
      goto exit;
    }
    if (loader->id_offset != -1) {
      id_value = value + loader->id_offset;
      id = parse_id_value(ctx, id_value);
      if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
        id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
      }
    } else if (loader->key_offset != -1) {
      key_value = value + loader->key_offset;
      id = loader_add(ctx, key_value);
    } else {
      id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
    }
  }
  if (id == GRN_ID_NIL) {
    /* Target record is not available. */
    goto exit;
  }

  for (i = 0; i < nvalues; i++, value = values_next(ctx, value)) {
    if (i == loader->id_offset || i == loader->key_offset) {
       /* Skip _id and _key, because it's already used to get id. */
       continue;
    }
    col = *cols;
    if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
      set_vector(ctx, col, id, value);
    } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
      set_weight_vector(ctx, col, id, value);
    } else {
      grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
    }
    if (ctx->rc != GRN_SUCCESS) {
      char column_name[GRN_TABLE_MAX_KEY_SIZE];
      unsigned int column_name_size;
      grn_loader_save_error(ctx, loader);
      column_name_size = grn_obj_name(ctx, col, column_name,
                                      GRN_TABLE_MAX_KEY_SIZE);
      report_set_column_value_failure(ctx, key_value,
                                      column_name, column_name_size,
                                      value);
      loader->n_column_errors++;
      ERRCLR(ctx);
    }
    cols++;
  }
  if (loader->each) {
    grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->each, 0);
    GRN_RECORD_SET(ctx, v, id);
    grn_expr_exec(ctx, loader->each, 0);
  }
  loader->nrecords++;
exit:
  if (is_record_load) {
    if (ctx->rc != GRN_SUCCESS) {
      loader->n_record_errors++;
    }
    if (loader->output_ids) {
      GRN_UINT32_PUT(ctx, &(loader->ids), id);
    }
    if (loader->output_errors) {
      GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
      grn_vector_add_element(ctx,
                             &(loader->error_messages),
                             ctx->errbuf,
                             strlen(ctx->errbuf),
                             0,
                             GRN_DB_TEXT);
    }
  }
  loader->values_size = begin;
  ERRCLR(ctx);
}
Example #13
0
static void
set_vector(grn_ctx *ctx, grn_obj *column, grn_id id, grn_obj *vector)
{
  int n = GRN_UINT32_VALUE(vector);
  grn_obj buf, *v = vector + 1;
  grn_id range_id;
  grn_obj *range;

  range_id = DB_OBJ(column)->range;
  range = grn_ctx_at(ctx, range_id);
  if (grn_obj_is_table(ctx, range)) {
    GRN_RECORD_INIT(&buf, GRN_OBJ_VECTOR, range_id);
    while (n--) {
      grn_bool cast_failed = GRN_FALSE;
      grn_obj record, *element = v;
      if (range_id != element->header.domain) {
        GRN_RECORD_INIT(&record, 0, range_id);
        if (grn_obj_cast(ctx, element, &record, GRN_TRUE)) {
          cast_failed = GRN_TRUE;
          ERR_CAST(column, range, element);
        }
        element = &record;
      }
      if (!cast_failed) {
        GRN_UINT32_PUT(ctx, &buf, GRN_RECORD_VALUE(element));
      }
      if (element == &record) { GRN_OBJ_FIN(ctx, element); }
      v = values_next(ctx, v);
    }
  } else {
    if (((struct _grn_type *)range)->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
      GRN_TEXT_INIT(&buf, GRN_OBJ_VECTOR);
      while (n--) {
        switch (v->header.domain) {
        case GRN_DB_TEXT :
        {
          grn_bool cast_failed = GRN_FALSE;
          grn_obj casted_element, *element = v;
          if (range_id != element->header.domain) {
            GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
            if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
              cast_failed = GRN_TRUE;
              ERR_CAST(column, range, element);
            }
            element = &casted_element;
          }
          if (!cast_failed) {
            grn_vector_add_element(ctx, &buf,
                                   GRN_TEXT_VALUE(element),
                                   GRN_TEXT_LEN(element),
                                   0,
                                   element->header.domain);
          }
          if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
          break;
        }
        case GRN_JSON_LOAD_OPEN_BRACE :
          add_weight_vector(ctx, column, v, &buf);
          n -= GRN_UINT32_VALUE(v);
          break;
        default :
          ERR(GRN_INVALID_ARGUMENT, "array must contain string or object");
          break;
        }
        v = values_next(ctx, v);
      }
    } else {
      grn_id value_size = ((grn_db_obj *)range)->range;
      GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, range_id);
      while (n--) {
        grn_bool cast_failed = GRN_FALSE;
        grn_obj casted_element, *element = v;
        if (range_id != element->header.domain) {
          GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
          if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
            cast_failed = GRN_TRUE;
            ERR_CAST(column, range, element);
          }
          element = &casted_element;
        }
        if (!cast_failed) {
          grn_bulk_write(ctx, &buf, GRN_TEXT_VALUE(element), value_size);
        }
        if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
        v = values_next(ctx, v);
      }
    }
  }
  grn_obj_set_value(ctx, column, id, &buf, GRN_OBJ_SET);
  GRN_OBJ_FIN(ctx, &buf);
}
Example #14
0
static grn_obj *
func_vector_slice(grn_ctx *ctx, int n_args, grn_obj **args,
                  grn_user_data *user_data)
{
  grn_obj *target;
  grn_obj *from_raw = NULL;
  grn_obj *length_raw = NULL;
  int64_t from = 0;
  int64_t length = -1;
  uint32_t to = 0;
  uint32_t size = 0;
  grn_obj *slice;

  if (n_args < 2 || n_args > 3) {
    GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
                     "vector_slice(): wrong number of arguments (%d for 2..3)",
                     n_args);
    return NULL;
  }

  target = args[0];
  from_raw = args[1];
  if (n_args == 3) {
    length_raw = args[2];
  }
  switch (target->header.type) {
  case GRN_VECTOR :
  case GRN_PVECTOR :
  case GRN_UVECTOR :
    size = grn_vector_size(ctx, target);
    break;
  default :
    {
      grn_obj inspected;

      GRN_TEXT_INIT(&inspected, 0);
      grn_inspect(ctx, target, &inspected);
      GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
                       "vector_slice(): target object must be vector: <%.*s>",
                       (int)GRN_TEXT_LEN(&inspected),
                       GRN_TEXT_VALUE(&inspected));
      GRN_OBJ_FIN(ctx, &inspected);
      return NULL;
    }
    break;
  }

  if (!grn_type_id_is_number_family(ctx, from_raw->header.domain)) {
    grn_obj inspected;

    GRN_TEXT_INIT(&inspected, 0);
    grn_inspect(ctx, &inspected, from_raw);
    GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
                     "vector_slice(): from must be a number: <%.*s>",
                     (int)GRN_TEXT_LEN(&inspected),
                     GRN_TEXT_VALUE(&inspected));
    GRN_OBJ_FIN(ctx, &inspected);
    return NULL;
  }
  if (from_raw->header.domain == GRN_DB_INT32) {
    from = GRN_INT32_VALUE(from_raw);
  } else if (from_raw->header.domain == GRN_DB_INT64) {
    from = GRN_INT64_VALUE(from_raw);
  } else {
    grn_obj buffer;
    grn_rc rc;

    GRN_INT64_INIT(&buffer, 0);
    rc = grn_obj_cast(ctx, from_raw, &buffer, GRN_FALSE);
    if (rc == GRN_SUCCESS) {
      from = GRN_INT64_VALUE(&buffer);
    }
    GRN_OBJ_FIN(ctx, &buffer);

    if (rc != GRN_SUCCESS) {
      grn_obj inspected;

      GRN_TEXT_INIT(&inspected, 0);
      grn_inspect(ctx, &inspected, from_raw);
      GRN_PLUGIN_ERROR(ctx, rc,
                       "vector_slice(): "
                       "failed to cast from value to number: <%.*s>",
                       (int)GRN_TEXT_LEN(&inspected),
                       GRN_TEXT_VALUE(&inspected));
      GRN_OBJ_FIN(ctx, &inspected);
      return NULL;
    }
  }

  if (length_raw) {
    if (!grn_type_id_is_number_family(ctx, length_raw->header.domain)) {
      grn_obj inspected;

      GRN_TEXT_INIT(&inspected, 0);
      grn_inspect(ctx, &inspected, length_raw);
      GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
                       "vector_slice(): length must be a number: <%.*s>",
                       (int)GRN_TEXT_LEN(&inspected),
                       GRN_TEXT_VALUE(&inspected));
      GRN_OBJ_FIN(ctx, &inspected);
      return NULL;
    }
    if (length_raw->header.domain == GRN_DB_INT32) {
      length = GRN_INT32_VALUE(length_raw);
    } else if (length_raw->header.domain == GRN_DB_INT64) {
      length = GRN_INT64_VALUE(length_raw);
    } else {
      grn_obj buffer;
      grn_rc rc;

      GRN_INT64_INIT(&buffer, 0);
      rc = grn_obj_cast(ctx, length_raw, &buffer, GRN_FALSE);
      if (rc == GRN_SUCCESS) {
        length = GRN_INT64_VALUE(&buffer);
      }
      GRN_OBJ_FIN(ctx, &buffer);

      if (rc != GRN_SUCCESS) {
        grn_obj inspected;

        GRN_TEXT_INIT(&inspected, 0);
        grn_inspect(ctx, &inspected, length_raw);
        GRN_PLUGIN_ERROR(ctx, rc,
                         "vector_slice(): "
                         "failed to cast length value to number: <%.*s>",
                         (int)GRN_TEXT_LEN(&inspected),
                         GRN_TEXT_VALUE(&inspected));
        GRN_OBJ_FIN(ctx, &inspected);
        return NULL;
      }
    }
  }

  slice = grn_plugin_proc_alloc(ctx, user_data, target->header.domain, GRN_OBJ_VECTOR);
  if (!slice) {
    return NULL;
  }

  if (target->header.flags & GRN_OBJ_WITH_WEIGHT) {
    slice->header.flags |= GRN_OBJ_WITH_WEIGHT;
  }

  if (length < 0) {
    length = size + length + 1;
  }

  if (length > size) {
    length = size;
  }

  if (length <= 0) {
    return slice;
  }

  while (from < 0) {
    from += size;
  }

  to = from + length;
  if (to > size) {
    to = size;
  }

  switch (target->header.type) {
  case GRN_VECTOR :
    {
      unsigned int i;
      for (i = from; i < to; i++) {
        const char *content;
        unsigned int content_length;
        unsigned int weight;
        grn_id domain;
        content_length = grn_vector_get_element(ctx, target, i,
                                                &content, &weight, &domain);
        grn_vector_add_element(ctx, slice,
                               content, content_length, weight, domain);
      }
    }
    break;
  case GRN_PVECTOR :
    {
      unsigned int i;
      for (i = from; i < to; i++) {
        grn_obj *element = GRN_PTR_VALUE_AT(target, i);
        GRN_PTR_PUT(ctx, slice, element);
      }
    }
    break;
  case GRN_UVECTOR :
    {
      unsigned int i;
      for (i = from; i < to; i++) {
        grn_id id;
        unsigned int weight;
        id = grn_uvector_get_element(ctx, target, i, &weight);
        grn_uvector_add_element(ctx, slice, id, weight);
      }
    }
    break;
  }

  return slice;
}