Exemplo n.º 1
0
int
rb_grn_table_cursor_order_by_to_flag (unsigned char table_type,
				      VALUE rb_table,
				      VALUE rb_order_by)
{
    int flag = 0;

    if (NIL_P(rb_order_by)) {
	if (table_type == GRN_TABLE_PAT_KEY) {
	    flag |= GRN_CURSOR_BY_KEY;
	} else {
	    flag |= GRN_CURSOR_BY_ID;
	}
    } else if (rb_grn_equal_option(rb_order_by, "id")) {
	flag |= GRN_CURSOR_BY_ID;
    } else if (rb_grn_equal_option(rb_order_by, "key")) {
	if (table_type != GRN_TABLE_PAT_KEY) {
	    rb_raise(rb_eArgError,
		     "order_by => :key is available "
		     "only for Groonga::PatriciaTrie: %s",
		     rb_grn_inspect(rb_table));
	}
	flag |= GRN_CURSOR_BY_KEY;
    } else {
	rb_raise(rb_eArgError,
		 "order_by should be one of [:id%s]: %s",
		 table_type == GRN_TABLE_PAT_KEY ? ", :key" : "",
		 rb_grn_inspect(rb_order_by));
    }

    return flag;
}
Exemplo n.º 2
0
grn_obj *
rb_grn_key_from_ruby_object (VALUE rb_key, grn_ctx *context,
                             grn_obj *key, grn_id domain_id, grn_obj *domain,
                             VALUE related_object)
{
    grn_id id;

    if (!domain)
        return RVAL2GRNBULK(rb_key, context, key);

    switch (domain->header.type) {
    case GRN_TYPE:
        return RVAL2GRNBULK_WITH_TYPE(rb_key, context, key, domain_id, domain);
        break;
    case GRN_TABLE_HASH_KEY:
    case GRN_TABLE_PAT_KEY:
    case GRN_TABLE_DAT_KEY:
    case GRN_TABLE_NO_KEY:
        id = RVAL2GRNID(rb_key, context, domain, related_object);
        break;
    default:
        if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_key, rb_cInteger)))
            rb_raise(rb_eGrnError,
                     "should be unsigned integer: <%s>: <%s>",
                     rb_grn_inspect(rb_key),
                     rb_grn_inspect(related_object));

        id = NUM2UINT(rb_key);
        break;
    }

    GRN_TEXT_SET(context, key, &id, sizeof(id));
    return key;
}
Exemplo n.º 3
0
grn_id
rb_grn_id_from_ruby_object (VALUE object, grn_ctx *context, grn_obj *table,
                            VALUE related_object)
{
    VALUE rb_id;

    if (NIL_P(object))
        return Qnil;

    if (RVAL2CBOOL(rb_obj_is_kind_of(object, rb_cGrnRecord))) {
        VALUE rb_table;
        rb_table = rb_funcall(object, rb_intern("table"), 0);
        if (table && RVAL2GRNOBJECT(rb_table, &context) != table) {
            VALUE rb_expected_table;

            rb_expected_table =
                GRNOBJECT2RVAL(Qnil, context, table, GRN_FALSE);
            rb_raise(rb_eGrnError,
                     "wrong table: expected <%s>: actual <%s>",
                     rb_grn_inspect(rb_expected_table),
                     rb_grn_inspect(rb_table));
        }
        rb_id = rb_funcall(object, rb_intern("id"), 0);
    } else {
        rb_id = object;
    }

    if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_id, rb_cInteger)))
        rb_raise(rb_eGrnError,
                 "should be unsigned integer or Groogna::Record: <%s>: <%s>",
                 rb_grn_inspect(object),
                 rb_grn_inspect(related_object));

    return NUM2UINT(rb_id);
}
Exemplo n.º 4
0
/*
 * 名前が _name_ の型を作成する。
 *
 * @overload new(name, options={})
 *   @param name [String] 作成する型の名前
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value
 *   @option options [Symbol] :type (:variable)
 *     :integer(符号付き整数)、:int(:integerの省略
 *     形)、:unsigned_integer(符号なし整
 *     数)、:uint(:unsigned_integerの省略形)、:float(浮動小数点
 *     数)、:variable(可変長文字列)のいずれかを指定する。省略した場
 *     合は:variableを指定したものと扱う。
 *     :variableを指定した場合は必ず +:size+ を指定しなければいけない。
 *   @option options [Context] :context
 *     型の作成時に利用するGroonga::Contextを指定する。省略すると
 *     Groonga::Context.defaultを用いる。
 *   @option options [Integer] :size
 *     +:option+ が:variableの場合は最大長、それ以外の場合は長さを
 *     指定する(単位:byte)。
 */
static VALUE
rb_grn_type_initialize (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context;
    grn_obj *type;
    const char *name = NULL;
    unsigned name_size, size = 0;
    grn_obj_flags flags = 0;
    VALUE rb_name, options, rb_context, rb_type, rb_size;

    rb_scan_args(argc, argv, "11", &rb_name, &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "type", &rb_type,
                        "size", &rb_size,
                        NULL);

    name = StringValuePtr(rb_name);
    name_size = RSTRING_LEN(rb_name);

    context = rb_grn_context_ensure(&rb_context);

    if (NIL_P(rb_type) ||
        rb_grn_equal_option(rb_type, "variable")) {
        flags = GRN_OBJ_KEY_VAR_SIZE;
    } else if (rb_grn_equal_option(rb_type, "integer") ||
               rb_grn_equal_option(rb_type, "int")) {
        flags = GRN_OBJ_KEY_INT;
        size = sizeof(int);
    } else if (rb_grn_equal_option(rb_type, "unsigned_integer") ||
               rb_grn_equal_option(rb_type, "uint")) {
        flags = GRN_OBJ_KEY_UINT;
        size = sizeof(unsigned int);
    } else if (rb_grn_equal_option(rb_type, "float")) {
        flags = GRN_OBJ_KEY_FLOAT;
        size = sizeof(double);
    } else {
        rb_raise(rb_eArgError,
                 ":type should be one of "
                 "[:integer, :int, :unsigned_integer, :uint, "
                 ":float, :variable]: %s",
                 rb_grn_inspect(options));
    }

    if (NIL_P(rb_size)) {
        if (size == 0)
            rb_raise(rb_eArgError, "size is missing: %s",
                     rb_grn_inspect(options));
    } else {
        size = NUM2UINT(rb_size);
    }

    type = grn_type_create(context, name, name_size, flags, size);
    rb_grn_object_assign(Qnil, self, rb_context, context, type);
    rb_grn_context_check(context, rb_ary_new4(argc, argv));

    return Qnil;
}
Exemplo n.º 5
0
static void
rb_grn_uvector_from_ruby_object_reference (UVectorFromRubyData *data)
{
    VALUE object;
    grn_ctx *context;
    grn_obj *uvector;
    VALUE related_object;
    VALUE *rb_values;
    int i, n;

    object = data->object;
    context = data->context;
    uvector = data->uvector;
    related_object = data->related_object;

    n = RARRAY_LEN(object);
    rb_values = RARRAY_PTR(object);
    for (i = 0; i < n; i++) {
        VALUE rb_value;
        grn_id id;
        void *grn_value;
        ID id_record_raw_id;

        rb_value = rb_values[i];
        switch (TYPE(rb_value)) {
        case T_FIXNUM:
            id = NUM2UINT(rb_value);
            break;
        default:
            CONST_ID(id_record_raw_id, "record_raw_id");
            if (rb_respond_to(rb_value, id_record_raw_id)) {
                id = NUM2UINT(rb_funcall(rb_value, id_record_raw_id, 0));
            } else {
                rb_raise(rb_eArgError,
                         "uvector value should be one of "
                         "[Fixnum or object that has #record_raw_id]: "
                         "%s (%s): %s",
                         rb_grn_inspect(rb_value),
                         rb_grn_inspect(object),
                         rb_grn_inspect(related_object));
            }
            break;
        }
        grn_value = &id;
        grn_bulk_write(context, uvector, grn_value, sizeof(grn_id));
    }

    data->succeeded = GRN_TRUE;
}
Exemplo n.º 6
0
void
rb_grn_scan_options (VALUE options, ...)
{
    VALUE original_options = options;
    VALUE available_keys;
    const char *key;
    VALUE *value;
    va_list args;

    options = rb_grn_check_convert_to_hash(options);
    if (NIL_P(options)) {
        if (NIL_P(original_options)) {
            options = rb_hash_new();
        } else {
            rb_raise(rb_eArgError,
                     "options must be Hash: %s",
                     rb_grn_inspect(original_options));
        }
    } else if (options == original_options) {
        options = rb_funcall(options, rb_intern("dup"), 0);
    }

    available_keys = rb_ary_new();
    va_start(args, options);
    key = va_arg(args, const char *);
    while (key) {
        VALUE rb_key;
        value = va_arg(args, VALUE *);

        rb_key = RB_GRN_INTERN(key);
        rb_ary_push(available_keys, rb_key);
        *value = rb_funcall(options, rb_intern("delete"), 1, rb_key);
        if (NIL_P(*value)) {
            rb_key = rb_str_new_cstr(key);
            *value = rb_funcall(options, rb_intern("delete"), 1, rb_key);
        }

        key = va_arg(args, const char *);
    }
    va_end(args);

    if (RVAL2CBOOL(rb_funcall(options, rb_intern("empty?"), 0)))
        return;

    rb_raise(rb_eArgError,
             "unexpected key(s) exist: %s: available keys: %s",
             rb_grn_inspect(rb_funcall(options, rb_intern("keys"), 0)),
             rb_grn_inspect(available_keys));
}
Exemplo n.º 7
0
VALUE
rb_grn_context_to_exception (grn_ctx *context, VALUE related_object)
{
    VALUE exception, exception_class;
    const char *message;
    grn_obj bulk;

    if (context->rc == GRN_SUCCESS)
	return Qnil;

    exception_class = rb_grn_rc_to_exception(context->rc);
    message = rb_grn_rc_to_message(context->rc);

    GRN_OBJ_INIT(&bulk, GRN_BULK, 0, GRN_ID_NIL);
    GRN_TEXT_PUTS(context, &bulk, message);
    GRN_TEXT_PUTS(context, &bulk, ": ");
    GRN_TEXT_PUTS(context, &bulk, context->errbuf);
    if (!NIL_P(related_object)) {
	GRN_TEXT_PUTS(context, &bulk, ": ");
	GRN_TEXT_PUTS(context, &bulk, rb_grn_inspect(related_object));
    }
    GRN_TEXT_PUTS(context, &bulk, "\n");
    GRN_TEXT_PUTS(context, &bulk, context->errfile);
    GRN_TEXT_PUTS(context, &bulk, ":");
    grn_text_itoa(context, &bulk, context->errline);
    GRN_TEXT_PUTS(context, &bulk, ": ");
    GRN_TEXT_PUTS(context, &bulk, context->errfunc);
    GRN_TEXT_PUTS(context, &bulk, "()");
    exception = rb_funcall(exception_class, rb_intern("new"), 1,
			   rb_str_new(GRN_BULK_HEAD(&bulk),
				      GRN_BULK_VSIZE(&bulk)));
    grn_obj_unlink(context, &bulk);

    return exception;
}
Exemplo n.º 8
0
static grn_table_cursor *
rb_grn_patricia_trie_open_grn_rk_cursor (int argc, VALUE *argv, VALUE self,
					     grn_ctx **context)
{
    grn_obj *table;
    grn_table_cursor *cursor;
    void *prefix = NULL;
    unsigned prefix_size = 0;
    int offset = 0, limit = -1;
    int flags = GRN_CURSOR_PREFIX | GRN_CURSOR_RK;
    VALUE options, rb_prefix, rb_key_bytes, rb_key_bits;
    VALUE rb_greater_than, rb_less_than, rb_offset, rb_limit;

    rb_grn_table_deconstruct((RbGrnTable *)SELF(self), &table, context,
			     NULL, NULL,
			     NULL, NULL, NULL,
			     NULL);

    rb_scan_args(argc, argv, "11", &rb_prefix, &options);

    rb_grn_scan_options(options,
			"key_bytes", &rb_key_bytes,
                        "key_bites", &rb_key_bits,
                        "offset", &rb_offset,
                        "limit", &rb_limit,
			"greater_than", &rb_greater_than,
			"less_than", &rb_less_than,
			NULL);

    prefix = StringValuePtr(rb_prefix);
    if (!NIL_P(rb_key_bytes) && !NIL_P(rb_key_bits)) {
	rb_raise(rb_eArgError,
		 "should not specify both :key_bytes and :key_bits once: %s",
		 rb_grn_inspect(rb_ary_new4(argc, argv)));
    } else if (!NIL_P(rb_key_bytes)) {
	prefix_size = NUM2UINT(rb_key_bytes);
    } else if (!NIL_P(rb_key_bits)) {
	prefix_size = NUM2UINT(rb_key_bits);
	flags |= GRN_CURSOR_SIZE_BY_BIT;
    } else {
	prefix_size = RSTRING_LEN(rb_prefix);
    }
    if (!NIL_P(rb_offset))
	offset = NUM2INT(rb_offset);
    if (!NIL_P(rb_limit))
	limit = NUM2INT(rb_limit);

    if (RVAL2CBOOL(rb_greater_than))
	flags |= GRN_CURSOR_GT;
    if (RVAL2CBOOL(rb_less_than))
	flags |= GRN_CURSOR_LT;

    cursor = grn_table_cursor_open(*context, table,
				   prefix, prefix_size,
				   NULL, 0,
				   offset, limit, flags);
    rb_grn_context_check(*context, self);

    return cursor;
}
Exemplo n.º 9
0
/*
 * Flush memory mapped data to disk.
 *
 * @overload flush(options={})
 *   @param [::Hash] options
 *   @option options [Boolean] :recursive (true) Whether to flush objects
 *     which a target object has recursively.
 *   @return [void]
 */
static VALUE
rb_grn_flushable_flush (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *object = NULL;
    VALUE rb_recursive_p;
    VALUE rb_options;

    rb_scan_args(argc, argv, "01", &rb_options);
    rb_grn_scan_options(rb_options,
                        "recursive", &rb_recursive_p,
                        NULL);
    if (NIL_P(rb_recursive_p)) {
        rb_recursive_p = Qtrue;
    }

    rb_grn_object_deconstruct(SELF(self), &object, &context,
                              NULL, NULL, NULL, NULL);
    if (!object) {
        rb_raise(rb_eGrnClosed,
                 "can't access already closed Groonga object: <%s>",
                 rb_grn_inspect(self));
    }

    if (RVAL2CBOOL(rb_recursive_p)) {
        grn_obj_flush_recursive(context, object);
    } else {
        grn_obj_flush(context, object);
    }
    rb_grn_context_check(context, self);

    return Qnil;
}
Exemplo n.º 10
0
/*
 * _table_ の _key_ に対応するカラム _column_name_ の値を設定する。
 * _key_ に対応するレコードがない場合は新しく作成される。
 *
 * 0.9.0から値ではなくカラムの値を設定するようになった。
 *
 * @overload []=(key, values)
 *   @param [::Hash] values
 *     keyに対応させるカラムの値。{ :column_name => value, ... }の形で設定する。
 */
static VALUE
rb_grn_table_key_support_array_set (VALUE self, VALUE rb_key, VALUE rb_values)
{
    grn_id id;
    SetValueData data;
    grn_ctx *context;
    grn_obj *table;

    rb_grn_table_key_support_deconstruct(SELF(self), &table, &context,
                                         NULL, NULL, NULL,
                                         NULL, NULL, NULL,
                                         NULL);

    id = rb_grn_table_key_support_add_raw(self, rb_key, NULL);

    if (id == GRN_ID_NIL) {
        rb_raise(rb_eGrnError,
                 "failed to add record: %s",
                 rb_grn_inspect(rb_ary_new3(3, self, rb_key, rb_values)));
    }

    data.self = self;
    data.id = id;
    data.table = table;
    data.rb_grn_object.context = context;
    rb_iterate(rb_each, rb_values, set_value, (VALUE)&data);

    return Qnil;
}
Exemplo n.º 11
0
/*
 * _table_ の _key_ に対応するカラム _name_ の値を設定する。
 * _key_ に対応するレコードがない場合は新しく作成される。
 *
 * @overload set_column_value(key, name, value)
 * @overload set_column_value(id, name, value, {:id=>true})
 */
static VALUE
rb_grn_table_key_support_set_column_value (int argc, VALUE *argv, VALUE self)
{
    grn_id id;
    VALUE rb_key, rb_id_or_key, rb_name, rb_value, rb_options;

    rb_scan_args(argc, argv, "31",
                 &rb_id_or_key, &rb_name, &rb_value, &rb_options);
    if (!NIL_P(rb_options)) {
        VALUE rb_option_id;
        rb_grn_scan_options(rb_options,
                            "id", &rb_option_id,
                            NULL);
        if (RVAL2CBOOL(rb_option_id)) {
            VALUE rb_id = rb_id_or_key;
            return rb_grn_table_set_column_value(self, rb_id, rb_name, rb_value);
        }
    }

    rb_key = rb_id_or_key;
    id = rb_grn_table_key_support_add_raw(self, rb_key, NULL);
    if (id == GRN_ID_NIL) {
        rb_raise(rb_eGrnError,
                 "failed to add record: %s",
                 rb_grn_inspect(rb_ary_new3(4,
                                            self, rb_key,
                                            rb_name, rb_value)));
    }

    return rb_grn_table_set_column_value_raw(self, id, rb_name, rb_value);
}
Exemplo n.º 12
0
grn_operator
rb_grn_operator_from_ruby_object (VALUE rb_operator)
{
    grn_operator operator = GRN_OP_OR;

    if (NIL_P(rb_operator) ||
            rb_grn_equal_option(rb_operator, "or") ||
            rb_grn_equal_option(rb_operator, "||")) {
        operator = GRN_OP_OR;
    } else if (rb_grn_equal_option(rb_operator, "and") ||
               rb_grn_equal_option(rb_operator, "+") ||
               rb_grn_equal_option(rb_operator, "&&")) {
        operator = GRN_OP_AND;
    } else if (rb_grn_equal_option(rb_operator, "but") ||
               rb_grn_equal_option(rb_operator, "not") ||
               rb_grn_equal_option(rb_operator, "-")) {
        operator = GRN_OP_BUT;
    } else if (rb_grn_equal_option(rb_operator, "adjust") ||
               rb_grn_equal_option(rb_operator, ">")) {
        operator = GRN_OP_ADJUST;
    } else {
        rb_raise(rb_eArgError,
                 "operator should be one of "
                 "[:or, :||, :and, :+, :&&, :but, :not, :-, :adjust, :>]: <%s>",
                 rb_grn_inspect(rb_operator));
    }

    return operator;
}
Exemplo n.º 13
0
grn_obj *
rb_grn_uvector_from_ruby_object (VALUE object, grn_ctx *context,
                                 grn_obj *uvector, VALUE related_object)
{
    UVectorFromRubyData data;

    if (NIL_P(object))
        return NULL;

    data.domain = grn_ctx_at(context, uvector->header.domain);
    if (!data.domain) {
        rb_raise(rb_eArgError,
                 "unknown domain uvector can't be converted: <%s>",
                 rb_grn_inspect(related_object));
    }

    GRN_OBJ_INIT(&(data.element_buffer), GRN_BULK, 0, uvector->header.domain);

    data.object = object;
    data.context = context;
    data.uvector = uvector;
    data.related_object = related_object;
    data.succeeded = GRN_FALSE;

    rb_ensure(rb_grn_uvector_from_ruby_object_body, (VALUE)(&data),
              rb_grn_uvector_from_ruby_object_ensure, (VALUE)(&data));

    if (!data.succeeded) {
        return NULL;
    }

    return uvector;
}
Exemplo n.º 14
0
static VALUE
rb_grn_uvector_from_ruby_object_body (VALUE user_data)
{
    UVectorFromRubyData *data = (UVectorFromRubyData *)user_data;
    grn_obj *domain;

    domain = data->domain;
    switch (domain->header.type) {
    case GRN_TYPE:
        rb_grn_uvector_from_ruby_object_type(data);
        break;
    case GRN_TABLE_HASH_KEY:
    case GRN_TABLE_PAT_KEY:
    case GRN_TABLE_DAT_KEY:
    case GRN_TABLE_NO_KEY:
        rb_grn_uvector_from_ruby_object_reference(data);
        break;
    default:
        rb_raise(rb_eTypeError,
                 "can't convert to unknown domain uvector: %s(%#x): <%s>",
                 rb_grn_inspect_type(domain->header.type),
                 domain->header.type,
                 rb_grn_inspect(data->related_object));
        break;
    }

    return Qnil;
}
Exemplo n.º 15
0
/*
 * Returns whether the column is compressed or not. If
 * @type@ is specified, it returns whether the column is
 * compressed by @type@ or not.
 * @overload compressed?
 *   @return [Boolean] whether the column is compressed or not.
 * @overload compressed?(type)
 *   @param [:zlib, :lz4] type (nil)
 *   @return [Boolean] whether specified compressed type is used or not.
 * @since 1.3.1
 */
static VALUE
rb_grn_variable_size_column_compressed_p (int argc, VALUE *argv, VALUE self)
{
    RbGrnVariableSizeColumn *rb_grn_column;
    grn_ctx *context = NULL;
    grn_obj *column;
    grn_obj_flags flags;
    VALUE type;
    grn_bool compressed_p = GRN_FALSE;
    grn_bool accept_any_type = GRN_FALSE;
    grn_bool need_zlib_check = GRN_FALSE;
    grn_bool need_lz4_check = GRN_FALSE;

    rb_scan_args(argc, argv, "01", &type);

    if (NIL_P(type)) {
        accept_any_type = GRN_TRUE;
    } else {
        if (rb_grn_equal_option(type, "zlib")) {
            need_zlib_check = GRN_TRUE;
        } else if (rb_grn_equal_option(type, "lzo")) {
            /* TODO: for backward compatibility */
            need_lz4_check = GRN_TRUE;
        } else if (rb_grn_equal_option(type, "lz4")) {
            need_lz4_check = GRN_TRUE;
        } else {
            rb_raise(rb_eArgError,
                     "compressed type should be <:zlib> or <:lz4>: <%s>",
                     rb_grn_inspect(type));
        }
    }

    rb_grn_column = SELF(self);
    rb_grn_object_deconstruct(RB_GRN_OBJECT(rb_grn_column), &column, &context,
                              NULL, NULL,
                              NULL, NULL);

    flags = column->header.flags;
    switch (flags & GRN_OBJ_COMPRESS_MASK) {
      case GRN_OBJ_COMPRESS_ZLIB:
        if (accept_any_type || need_zlib_check) {
            grn_obj support_p;
            GRN_BOOL_INIT(&support_p, 0);
            grn_obj_get_info(context, NULL, GRN_INFO_SUPPORT_ZLIB, &support_p);
            compressed_p = GRN_BOOL_VALUE(&support_p);
        }
        break;
      case GRN_OBJ_COMPRESS_LZ4:
        if (accept_any_type || need_lz4_check) {
            grn_obj support_p;
            GRN_BOOL_INIT(&support_p, 0);
            grn_obj_get_info(context, NULL, GRN_INFO_SUPPORT_LZ4, &support_p);
            compressed_p = GRN_BOOL_VALUE(&support_p);
        }
        break;
    }

    return CBOOL2RVAL(compressed_p);
}
Exemplo n.º 16
0
/*
 * call-seq:
 *   table.find(key) -> Groonga::Record
 *
 * テーブルの_key_に対応するレコードを返す。
 *
 * 0.9.0から非推奨。代わりにtable[key]を使うこと。
 */
static VALUE
rb_grn_table_key_support_find (VALUE self, VALUE rb_key)
{
    rb_warn("#find is deprecated. Use #[] instead: %s",
	    rb_grn_inspect(self));

    return rb_grn_table_key_support_array_reference(self, rb_key);
}
Exemplo n.º 17
0
VALUE
rb_grn_obj_to_ruby_object (VALUE klass, grn_ctx *context,
                           grn_obj *obj, VALUE related_object)
{
    if (!obj)
        return Qnil;

/*     if (NIL_P(klass)) */
/*      klass = GRNOBJECT2RCLASS(obj); */

    switch (obj->header.type) {
    case GRN_VOID:
        if (GRN_BULK_VSIZE(obj) > 0)
            return rb_str_new(GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
        else
            return Qnil;
        break;
    case GRN_BULK:
        return GRNBULK2RVAL(context, obj, NULL, related_object);
        break;
    /* case GRN_PTR: */
    /* case GRN_UVECTOR: */
    /* case GRN_PVECTOR: */
    case GRN_VECTOR:
        return GRNVECTOR2RVAL(context, obj);
        break;
    /* case GRN_MSG: */
    /* case GRN_QUERY: */
    /* case GRN_ACCESSOR: */
    /* case GRN_SNIP: */
    /* case GRN_PATSNIP: */
    /* case GRN_CURSOR_TABLE_HASH_KEY: */
    /* case GRN_CURSOR_TABLE_PAT_KEY: */
    /* case GRN_CURSOR_TABLE_NO_KEY: */
    /* case GRN_CURSOR_COLUMN_INDEX: */
    /* case GRN_TYPE: */
    /* case GRN_PROC: */
    /* case GRN_EXPR: */
    /* case GRN_TABLE_HASH_KEY: */
    /* case GRN_TABLE_PAT_KEY: */
    /* case GRN_TABLE_DAT_KEY: */
    /* case GRN_TABLE_NO_KEY: */
    /* case GRN_DB: */
    /* case GRN_COLUMN_FIX_SIZE: */
    /* case GRN_COLUMN_VAR_SIZE: */
    /* case GRN_COLUMN_INDEX: */
    default:
        rb_raise(rb_eTypeError,
                 "unsupported groonga object: %s(%#x): <%s>",
                 rb_grn_inspect_type(obj->header.type),
                 obj->header.type,
                 rb_grn_inspect(related_object));
        break;
    }

    return Qnil;
}
Exemplo n.º 18
0
VALUE
rb_grn_value_to_ruby_object (grn_ctx *context,
			     grn_obj *value,
			     grn_obj *range,
			     VALUE related_object)
{
    if (!value)
	return Qnil;

    switch (value->header.type) {
      case GRN_VOID:
	return Qnil;
	break;
      case GRN_BULK:
	if (GRN_BULK_EMPTYP(value))
	    return Qnil;
	if (value->header.domain == GRN_ID_NIL && range)
	    value->header.domain = grn_obj_id(context, range);
	return GRNBULK2RVAL(context, value, range, related_object);
	break;
      case GRN_UVECTOR:
	{
	    VALUE rb_value, rb_range = Qnil;
	    grn_id *uvector, *uvector_end;

	    rb_value = rb_ary_new();
	    if (range)
		rb_range = GRNTABLE2RVAL(context, range, GRN_FALSE);
	    uvector = (grn_id *)GRN_BULK_HEAD(value);
	    uvector_end = (grn_id *)GRN_BULK_CURR(value);
	    for (; uvector < uvector_end; uvector++) {
		VALUE record = Qnil;
		if (*uvector != GRN_ID_NIL)
		    record = rb_grn_record_new(rb_range, *uvector, Qnil);
		rb_ary_push(rb_value, record);
	    }
	    return rb_value;
	}
	break;
      case GRN_VECTOR:
	return GRNVECTOR2RVAL(context, value);
	break;
      default:
	rb_raise(rb_eGrnError,
		 "unsupported value type: %s(%#x): %s",
		 rb_grn_inspect_type(value->header.type),
		 value->header.type,
		 rb_grn_inspect(related_object));
	break;
    }

    if (!range)
	return GRNOBJECT2RVAL(Qnil, context, value, GRN_FALSE);

    return Qnil;
}
Exemplo n.º 19
0
grn_obj *
rb_grn_uvector_from_ruby_object (VALUE object, grn_ctx *context,
				 grn_obj *uvector, VALUE related_object)
{
    VALUE *values;
    int i, n;

    if (NIL_P(object))
	return NULL;

    n = RARRAY_LEN(object);
    values = RARRAY_PTR(object);
    for (i = 0; i < n; i++) {
	VALUE value;
	grn_id id;
	void *grn_value;

	value = values[i];
	switch (TYPE(value)) {
	  case T_FIXNUM:
	    id = NUM2UINT(value);
	    break;
	  default:
	    if (rb_respond_to(value, rb_intern("record_raw_id"))) {
		id = NUM2UINT(rb_funcall(value, rb_intern("record_raw_id"), 0));
	    } else {
		grn_obj_unlink(context, uvector);
		rb_raise(rb_eArgError,
			 "uvector value should be one of "
			 "[Fixnum or object that has #record_raw_id]: "
			 "%s (%s): %s",
			 rb_grn_inspect(value),
			 rb_grn_inspect(object),
			 rb_grn_inspect(related_object));
	    }
	    break;
	}
	grn_value = &id;
	grn_bulk_write(context, uvector, grn_value, sizeof(grn_id));
    }

    return uvector;
}
Exemplo n.º 20
0
static VALUE
set_value (VALUE args, SetValueData *data)
{
    VALUE rb_name, rb_value, rb_column;
    RbGrnObject *rb_grn_object;

    rb_name = rb_ary_entry(args, 0);
    rb_value = rb_ary_entry(args, 1);

    rb_column = rb_grn_table_get_column(data->self, rb_name);
    if (NIL_P(rb_column)) {
        rb_raise(rb_eGrnNoSuchColumn,
                 "no such column: <%s>: <%s>",
                 rb_grn_inspect(rb_name), rb_grn_inspect(data->self));
    }

    rb_grn_object = RB_GRN_OBJECT(DATA_PTR(rb_column));
    return rb_grn_object_set_raw(rb_grn_object,
                                 data->id, rb_value, GRN_OBJ_SET, data->self);
}
Exemplo n.º 21
0
void
rb_grn_scan_options (VALUE options, ...)
{
    VALUE available_keys;
    const char *key;
    VALUE *value;
    va_list args;

    if (NIL_P(options))
        options = rb_hash_new();
    else
        options = rb_funcall(options, rb_intern("dup"), 0);

    Check_Type(options, T_HASH);

    available_keys = rb_ary_new();
    va_start(args, options);
    key = va_arg(args, const char *);
    while (key) {
        VALUE rb_key;
        value = va_arg(args, VALUE *);

        rb_key = RB_GRN_INTERN(key);
        rb_ary_push(available_keys, rb_key);
        *value = rb_funcall(options, rb_intern("delete"), 1, rb_key);

        key = va_arg(args, const char *);
    }
    va_end(args);

    if (RVAL2CBOOL(rb_funcall(options, rb_intern("empty?"), 0)))
        return;

    rb_raise(rb_eArgError,
             "unexpected key(s) exist: %s: available keys: %s",
             rb_grn_inspect(rb_funcall(options, rb_intern("keys"), 0)),
             rb_grn_inspect(available_keys));
}
Exemplo n.º 22
0
static VALUE
rb_grn_table_key_support_set_value_by_key (VALUE self,
                                           VALUE rb_key, VALUE rb_value)
{
    grn_ctx *context;
    grn_obj *table;
    grn_id id;
    grn_obj *value;
    grn_rc rc;

    if (NIL_P(rb_key)) {
        rb_raise(rb_eArgError, "key should not be nil: <%s>",
                 rb_grn_inspect(self));
    }

    rb_grn_table_key_support_deconstruct(SELF(self), &table, &context,
                                         NULL, NULL, NULL,
                                         &value, NULL, NULL,
                                         NULL);

    id = rb_grn_table_key_support_add_raw(self, rb_key, NULL);
    if (GRN_ID_NIL == id) {
        rb_raise(rb_eGrnError,
                 "failed to add new record with key: <%s>: <%s>",
                 rb_grn_inspect(rb_key),
                 rb_grn_inspect(self));
    }

    GRN_BULK_REWIND(value);
    RVAL2GRNBULK(rb_value, context, value);
    rc = grn_obj_set_value(context, table, id, value, GRN_OBJ_SET);
    rb_grn_context_check(context, self);
    rb_grn_rc_check(rc, self);

    return rb_value;
}
Exemplo n.º 23
0
void
rb_grn_rc_check (grn_rc rc, VALUE related_object)
{
    VALUE exception;
    const char *message;

    exception = rb_grn_rc_to_exception(rc);
    if (NIL_P(exception))
        return;
    message = rb_grn_rc_to_message(rc);

    if (NIL_P(related_object))
        rb_raise(exception, "%s", message);
    else
        rb_raise(exception, "%s: %s", rb_grn_inspect(related_object),  message);
}
Exemplo n.º 24
0
/*
 * call-seq:
 *   snippet.execute(string) -> スニペットの配列
 *
 * _string_を走査し、スニペットを作成する。
 */
static VALUE
rb_grn_snippet_execute (VALUE self, VALUE rb_string)
{
    RbGrnSnippet *rb_grn_snippet;
    grn_rc rc;
    grn_ctx *context;
    grn_snip *snippet;
    char *string;
    unsigned int string_length;
    unsigned int i, n_results, max_tagged_length;
    VALUE rb_results;
    char *result;

    if (TYPE(rb_string) != T_STRING) {
	rb_raise(rb_eGrnInvalidArgument,
		 "snippet text must be String: <%s>",
		 rb_grn_inspect(rb_string));
    }

    rb_grn_snippet = SELF(self);
    context = rb_grn_snippet->context;
    snippet = rb_grn_snippet->snippet;

#ifdef HAVE_RUBY_ENCODING_H
    rb_string = rb_grn_context_rb_string_encode(context, rb_string);
#endif
    string = StringValuePtr(rb_string);
    string_length = RSTRING_LEN(rb_string);

    rc = grn_snip_exec(context, snippet, string, string_length,
                       &n_results, &max_tagged_length);
    rb_grn_rc_check(rc, self);

    rb_results = rb_ary_new2(n_results);
    result = ALLOCA_N(char, max_tagged_length);
    for (i = 0; i < n_results; i++) {
        VALUE rb_result;
        unsigned result_length;

        rc = grn_snip_get_result(context, snippet, i, result, &result_length);
        rb_grn_rc_check(rc, self);
        rb_result = rb_grn_context_rb_string_new(context, result, result_length);
        rb_ary_push(rb_results, rb_result);
    }

    return rb_results;
}
Exemplo n.º 25
0
int
rb_grn_table_cursor_order_to_flag (VALUE rb_order)
{
    int flag = 0;

    if (NIL_P(rb_order) ||
	rb_grn_equal_option(rb_order, "asc") ||
	rb_grn_equal_option(rb_order, "ascending")) {
	flag |= GRN_CURSOR_ASCENDING;
    } else if (rb_grn_equal_option(rb_order, "desc") ||
	       rb_grn_equal_option(rb_order, "descending")) {
	flag |= GRN_CURSOR_DESCENDING;
    } else {
	rb_raise(rb_eArgError,
		 "order should be one of "
		 "[:asc, :ascending, :desc, :descending]: %s",
		 rb_grn_inspect(rb_order));
    }

    return flag;
}
Exemplo n.º 26
0
VALUE
rb_grn_value_to_ruby_object (grn_ctx *context,
                             grn_obj *value,
                             grn_obj *range,
                             VALUE related_object)
{
    if (!value)
        return Qnil;

    switch (value->header.type) {
    case GRN_VOID:
        return Qnil;
        break;
    case GRN_BULK:
        if (GRN_BULK_EMPTYP(value))
            return Qnil;
        if (value->header.domain == GRN_ID_NIL && range)
            value->header.domain = grn_obj_id(context, range);
        return GRNBULK2RVAL(context, value, range, related_object);
        break;
    case GRN_UVECTOR:
        return GRNUVECTOR2RVAL(context, value, range, related_object);
        break;
    case GRN_VECTOR:
        return GRNVECTOR2RVAL(context, value);
        break;
    default:
        rb_raise(rb_eGrnError,
                 "unsupported value type: %s(%#x): %s",
                 rb_grn_inspect_type(value->header.type),
                 value->header.type,
                 rb_grn_inspect(related_object));
        break;
    }

    if (!range)
        return GRNOBJECT2RVAL(Qnil, context, value, GRN_FALSE);

    return Qnil;
}
Exemplo n.º 27
0
static grn_log_level
rb_grn_log_level_from_ruby_object (VALUE rb_level)
{
    grn_log_level level = GRN_LOG_NONE;

    if (NIL_P(rb_level)) {
        level = GRN_LOG_DEFAULT_LEVEL;
    } else if (rb_grn_equal_option(rb_level, "none")) {
        level = GRN_LOG_NONE;
    } else if (rb_grn_equal_option(rb_level, "emergency")) {
        level = GRN_LOG_EMERG;
    } else if (rb_grn_equal_option(rb_level, "alert")) {
        level = GRN_LOG_ALERT;
    } else if (rb_grn_equal_option(rb_level, "critical")) {
        level = GRN_LOG_CRIT;
    } else if (rb_grn_equal_option(rb_level, "error")) {
        level = GRN_LOG_ERROR;
    } else if (rb_grn_equal_option(rb_level, "warning")) {
        level = GRN_LOG_WARNING;
    } else if (rb_grn_equal_option(rb_level, "notice")) {
        level = GRN_LOG_NOTICE;
    } else if (rb_grn_equal_option(rb_level, "info")) {
        level = GRN_LOG_INFO;
    } else if (rb_grn_equal_option(rb_level, "debug")) {
        level = GRN_LOG_DEBUG;
    } else if (rb_grn_equal_option(rb_level, "dump")) {
        level = GRN_LOG_DUMP;
    } else {
        rb_raise(rb_eArgError,
                 "log level should be one of "
                 "[nil, :none, :emergency, :alert, :critical, :error, "
                 ":warning, :notice, :info, :debug, :dump]: %s",
                 rb_grn_inspect(rb_level));
    }

    return level;
}
Exemplo n.º 28
0
/*
 * call-seq:
 *   context[name] -> Groonga::Object or nil
 *   context[id]   -> Groonga::Object or nil
 *
 * コンテキスト管理下にあるオブジェクトを返す。
 *
 * _name_として文字列を指定した場合はオブジェクト名でオブジェ
 * クトを検索する。
 *
 * _id_として数値を指定した場合はオブジェクトIDでオブジェク
 * トを検索する。
 */
static VALUE
rb_grn_context_array_reference (VALUE self, VALUE name_or_id)
{
    grn_ctx *context;
    grn_obj *object;
    const char *name;
    unsigned int name_size;
    grn_id id;

    context = SELF(self);
    switch (TYPE(name_or_id)) {
      case T_SYMBOL:
	name = rb_id2name(SYM2ID(name_or_id));
	name_size = strlen(name);
	object = rb_grn_context_get_backward_compatibility(context,
							   name, name_size);
	break;
      case T_STRING:
	name = StringValuePtr(name_or_id);
	name_size = RSTRING_LEN(name_or_id);
	object = rb_grn_context_get_backward_compatibility(context,
							   name, name_size);
	break;
      case T_FIXNUM:
	id = NUM2UINT(name_or_id);
	object = grn_ctx_at(context, id);
	break;
      default:
	rb_raise(rb_eArgError,
		 "should be String, Symbol or unsigned integer: %s",
		 rb_grn_inspect(name_or_id));
	break;
    }

    return GRNOBJECT2RVAL(Qnil, context, object, RB_GRN_FALSE);
}
Exemplo n.º 29
0
/* FIXME: DON'T WORK!!! */
static VALUE
rb_grn_view_sort (int argc, VALUE *argv, VALUE self)
{
    VALUE rb_result = Qnil;

#ifdef WIN32
    rb_raise(rb_eNotImpError, "grn_view_add() isn't available on Windows.");
#else
    grn_ctx *context = NULL;
    grn_obj *view;
    grn_obj *result;
    grn_table_sort_key *keys;
    int i, n_keys;
    int n_records, offset = 0, limit = -1;
    VALUE rb_keys, options;
    VALUE rb_offset, rb_limit;
    VALUE *rb_sort_keys;
    grn_table_cursor *cursor;
    VALUE exception;
    grn_obj id;

    rb_grn_table_deconstruct(SELF(self), &view, &context,
                             NULL, NULL,
                             NULL, NULL, NULL,
                             NULL);

    rb_scan_args(argc, argv, "11", &rb_keys, &options);

    if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_keys, rb_cArray)))
        rb_raise(rb_eArgError, "keys should be an array of key: <%s>",
                 rb_grn_inspect(rb_keys));

    n_keys = RARRAY_LEN(rb_keys);
    rb_sort_keys = RARRAY_PTR(rb_keys);
    keys = ALLOCA_N(grn_table_sort_key, n_keys);
    for (i = 0; i < n_keys; i++) {
        VALUE rb_sort_options, rb_key, rb_resolved_key, rb_order;

        if (RVAL2CBOOL(rb_obj_is_kind_of(rb_sort_keys[i], rb_cHash))) {
            rb_sort_options = rb_sort_keys[i];
        } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_sort_keys[i], rb_cArray))) {
            rb_sort_options = rb_hash_new();
            rb_hash_aset(rb_sort_options,
                         RB_GRN_INTERN("key"),
                         rb_ary_entry(rb_sort_keys[i], 0));
            rb_hash_aset(rb_sort_options,
                         RB_GRN_INTERN("order"),
                         rb_ary_entry(rb_sort_keys[i], 1));
        } else {
            rb_sort_options = rb_hash_new();
            rb_hash_aset(rb_sort_options,
                         RB_GRN_INTERN("key"),
                         rb_sort_keys[i]);
        }
        rb_grn_scan_options(rb_sort_options,
                            "key", &rb_key,
                            "order", &rb_order,
                            NULL);
        if (RVAL2CBOOL(rb_obj_is_kind_of(rb_key, rb_cString))) {
            rb_resolved_key = rb_grn_table_get_column(self, rb_key);
        } else {
            rb_resolved_key = rb_key;
        }
        keys[i].key = RVAL2GRNOBJECT(rb_resolved_key, &context);
        if (!keys[i].key) {
            rb_raise(rb_eGrnNoSuchColumn,
                     "no such column: <%s>: <%s>",
                     rb_grn_inspect(rb_key), rb_grn_inspect(self));
        }
        if (NIL_P(rb_order)) {
            keys[i].flags = 0;
        } else if (rb_grn_equal_option(rb_order, "desc") ||
                   rb_grn_equal_option(rb_order, "descending")) {
            keys[i].flags = GRN_TABLE_SORT_DESC;
        } else if (rb_grn_equal_option(rb_order, "asc") ||
                   rb_grn_equal_option(rb_order, "ascending")) {
            keys[i].flags = GRN_TABLE_SORT_ASC;
        } else {
            rb_raise(rb_eArgError,
                     "order should be one of "
                     "[nil, :desc, :descending, :asc, :ascending]: %s",
                     rb_grn_inspect(rb_order));
        }
    }

    rb_grn_scan_options(options,
                        "offset", &rb_offset,
                        "limit", &rb_limit,
                        NULL);

    if (!NIL_P(rb_offset))
        offset = NUM2INT(rb_offset);
    if (!NIL_P(rb_limit))
        limit = NUM2INT(rb_limit);

    result = grn_table_create(context, NULL, 0, NULL, GRN_TABLE_VIEW,
                              NULL, NULL);
    grn_view_add(context, result,
                 grn_table_create(context, NULL, 0, NULL, GRN_TABLE_NO_KEY,
                                  NULL, grn_ctx_get(context, "People", strlen("People"))));
    grn_view_add(context, result,
                 grn_table_create(context, NULL, 0, NULL, GRN_TABLE_NO_KEY,
                                  NULL, grn_ctx_get(context, "People", strlen("People"))));
    n_records = grn_table_sort(context, view, offset, limit,
                               result, keys, n_keys);
    exception = rb_grn_context_to_exception(context, self);
    if (!NIL_P(exception)) {
        grn_obj_unlink(context, result);
        rb_exc_raise(exception);
    }

    rb_result = rb_ary_new();
    cursor = grn_table_cursor_open(context, result, NULL, 0, NULL, 0,
                                   0, -1, GRN_CURSOR_ASCENDING);
    GRN_TEXT_INIT(&id, 0);
    while (grn_table_cursor_next_o(context, cursor, &id) == GRN_SUCCESS) {
        rb_ary_push(rb_result, rb_grn_view_record_new(self, &id));
    }
    GRN_OBJ_FIN(context, &id);
    grn_table_cursor_close(context, cursor);
    grn_obj_unlink(context, result);
#endif

    return rb_result;
}
Exemplo n.º 30
0
/*
 * call-seq:
 *   column.select(options) {|record| ...} -> Groonga::Hash
 *   column.select(query, options) -> Groonga::Hash
 *   column.select(expression, options) -> Groonga::Hash
 *
 * カラムが所属するテーブルからブロックまたは文字列で指定し
 * た条件にマッチするレコードを返す。返されたテーブルには
 * +expression+という特異メソッドがあり、指定した条件を表し
 * ているGroonga::Expressionを取得できる。
 * Groonga::Expression#snippetを使うことにより、指定した条件
 * 用のスニペットを簡単に生成できる。
 *
 *   results = description_column.select do |column|
 *     column =~ "groonga"
 *   end
 *   snippet = results.expression.snippet([["<em>", "</em>"]])
 *   results.each do |record|
 *     puts "#{record['name']}の説明文の中で「groonga」が含まれる部分"
 *     snippet.execute(record["description"].each do |snippet|
 *       puts "---"
 *       puts "#{snippet}..."
 *       puts "---"
 *     end
 *   end
 *
 * 出力例
 *   Ruby/groongaの説明文の中で「groonga」が含まれる部分
 *   ---
 *   Ruby/<em>groonga</em>は<em>groonga</em>のいわゆるDB-APIの層の...
 *   ---
 *
 * _query_には「[カラム名]:[演算子][値]」という書式で条件を
 * 指定する。演算子は以下の通り。
 *
 * [なし]
 *   [カラム値] == [値]
 * [<tt>!</tt>]
 *   [カラム値] != [値]
 * [<tt><</tt>]
 *   [カラム値] < [値]
 * [<tt>></tt>]
 *   [カラム値] > [値]
 * [<tt><=</tt>]
 *   [カラム値] <= [値]
 * [<tt>>=</tt>]
 *   [カラム値] >= [値]
 * [<tt>@</tt>]
 *   [カラム値]が[値]を含んでいるかどうか
 *
 * 例:
 *   "groonga" # _column_カラムの値が"groonga"のレコードにマッチ
 *   "name:daijiro" # _column_カラムが属しているテーブルの
 *                  # "name"カラムの値が"daijiro"のレコードにマッチ
 *   "description:@groonga" # _column_カラムが属しているテーブルの
 *                          # "description"カラムが
 *                          # "groonga"を含んでいるレコードにマッチ
 *
 * _expression_には既に作成済みのGroonga::Expressionを渡す
 *
 * ブロックで条件を指定する場合は
 * Groonga::ColumnExpressionBuilderを参照。
 *
 * _options_に指定可能な値は以下の通り。
 *
 * [+:operator+]
 *   マッチしたレコードをどのように扱うか。指定可能な値は以
 *   下の通り。省略した場合はGroonga::Operation::OR。
 *
 *   [Groonga::Operation::OR]
 *     マッチしたレコードを追加。すでにレコードが追加され
 *     ている場合は何もしない。
 *   [Groonga::Operation::AND]
 *     マッチしたレコードのスコアを増加。マッチしなかった
 *     レコードを削除。
 *   [Groonga::Operation::BUT]
 *     マッチしたレコードを削除。
 *   [Groonga::Operation::ADJUST]
 *     マッチしたレコードのスコアを増加。
 *
 * [+:result+]
 *   検索結果を格納するテーブル。マッチしたレコードが追加さ
 *   れていく。省略した場合は新しくテーブルを作成して返す。
 *
 * [+:name+]
 *   条件の名前。省略した場合は名前を付けない。
 *
 * [+:syntax+]
 *   _query_の構文。省略した場合は+:query+。
 *
 *   参考: Groonga::Expression#parse.
 *
 * [+:allow_pragma+]
 *   query構文時にプラグマを利用するかどうか。省略した場合は
 *   利用する。
 *
 *   参考: Groonga::Expression#parse.
 *
 * [+:allow_column+]
 *   query構文時にカラム指定を利用するかどうか。省略した場合
 *   は利用する。
 *
 *   参考: Groonga::Expression#parse.
 *
 * [+:allow_update+]
 *   script構文時に更新操作を利用するかどうか。省略した場合
 *   は利用する。
 *
 *   参考: Groonga::Expression#parse.
 */
static VALUE
rb_grn_column_select (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context;
    grn_obj *table, *column, *result, *expression;
    grn_operator operator = GRN_OP_OR;
    VALUE options;
    VALUE rb_query, condition_or_options;
    VALUE rb_name, rb_operator, rb_result, rb_syntax;
    VALUE rb_allow_pragma, rb_allow_column, rb_allow_update;
    VALUE builder;
    VALUE rb_expression = Qnil;

    rb_query = Qnil;

    rb_scan_args(argc, argv, "02", &condition_or_options, &options);

    rb_grn_column_deconstruct(SELF(self), &column, &context,
			      NULL, NULL,
			      NULL, NULL, NULL);
    table = grn_column_table(context, column);

    if (RVAL2CBOOL(rb_obj_is_kind_of(condition_or_options, rb_cString))) {
        rb_query = condition_or_options;
    } else if (RVAL2CBOOL(rb_obj_is_kind_of(condition_or_options,
                                            rb_cGrnExpression))) {
        rb_expression = condition_or_options;
    } else {
        if (!NIL_P(options))
            rb_raise(rb_eArgError,
		     "should be [query_string, option_hash], "
		     "[expression, option_hash] "
		     "or [option_hash]: %s",
		     rb_grn_inspect(rb_ary_new4(argc, argv)));
        options = condition_or_options;
    }

    rb_grn_scan_options(options,
			"operator", &rb_operator,
			"result", &rb_result,
			"name", &rb_name,
			"syntax", &rb_syntax,
			"allow_pragma", &rb_allow_pragma,
			"allow_column", &rb_allow_column,
			"allow_update", &rb_allow_update,
			NULL);

    if (!NIL_P(rb_operator))
	operator = NUM2INT(rb_operator);

    if (NIL_P(rb_result)) {
	result = grn_table_create(context, NULL, 0, NULL,
				  GRN_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
				  table,
				  0);
	rb_result = GRNTABLE2RVAL(context, result, RB_GRN_TRUE);
    } else {
	result = RVAL2GRNTABLE(rb_result, &context);
    }

    if (NIL_P(rb_expression)) {
      builder = rb_grn_column_expression_builder_new(self, rb_name, rb_query);
      rb_funcall(builder, rb_intern("syntax="), 1, rb_syntax);
      rb_funcall(builder, rb_intern("allow_pragma="), 1, rb_allow_pragma);
      rb_funcall(builder, rb_intern("allow_column="), 1, rb_allow_column);
      rb_funcall(builder, rb_intern("allow_update="), 1, rb_allow_update);
      rb_expression = rb_grn_column_expression_builder_build(builder);
    }
    rb_grn_object_deconstruct(RB_GRN_OBJECT(DATA_PTR(rb_expression)),
                              &expression, NULL,
                              NULL, NULL, NULL, NULL);

    grn_table_select(context, table, expression, result, operator);
    rb_grn_context_check(context, self);

    rb_attr(rb_singleton_class(rb_result),
	    rb_intern("expression"),
	    RB_GRN_TRUE, RB_GRN_FALSE, RB_GRN_FALSE);
    rb_iv_set(rb_result, "@expression", rb_expression);

    return rb_result;
}