Esempio n. 1
0
/*
 * _constant_ を追加し、 _n_arguments_ 個の引数を取る _operation_ を追加する。
 *
 * @overload append_constant(constant, operation=Groonga::Operator::PUSH, n_arguments=1)
 *   @param [Object] constant 追加する _constant_
 *   @param [Groonga::Operator::XXX] operation 追加する _operation_
 *   @param [Integer] n_arguments _operation_ の取る引数
 * @return [Self] self
 */
static VALUE
rb_grn_expression_append_constant (int argc, VALUE *argv, VALUE self)
{
    VALUE rb_constant, rb_operator, rb_n_arguments;
    VALUE exception;
    grn_ctx *context = NULL;
    grn_obj *expression, *constant = NULL;
    grn_operator operator = GRN_OP_PUSH;
    int n_arguments = 1;

    rb_scan_args(argc, argv, "12", &rb_constant, &rb_operator, &rb_n_arguments);
    if (!NIL_P(rb_operator))
        operator = RVAL2GRNOPERATOR(rb_operator);
    if (!NIL_P(rb_n_arguments))
        n_arguments = NUM2INT(rb_n_arguments);

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL, NULL,
                                  NULL, NULL);

    RVAL2GRNOBJ(rb_constant, context, &constant);
    grn_expr_append_const(context, expression, constant, operator, n_arguments);

    exception = rb_grn_context_to_exception(context, self);
    grn_obj_unlink(context, constant);
    if (!NIL_P(exception))
        rb_exc_raise(exception);

    return self;
}
Esempio n. 2
0
/*
 * データベース内のオブジェクトを順番にブロックに渡す。
 *
 * @example すべてのオブジェクトの名前を表示する:
 *   database.each do |object|
 *     p object.name
 *   end
 *
 * @example すべてのオブジェクトの名前をID順で表示する:
 *   database.each(:order_by => :id) do |object|
 *     p object.name
 *   end
 *
 * @example すべてのオブジェクトの名前をキー名の降順で表示する:
 *   database.each(:order_by => :key, :order => :desc) do |object|
 *     p object.name
 *   end
 *
 * @overload each(options=nil)
 *   @macro [new] database.each.options
 *     @param options [::Hash]
 *     @yield [object]
 *     @option options :order
 *       +:asc+ または +:ascending+ を指定すると昇順にレコードを取
 *       り出す。(デフォルト)
 *       +:desc+ または +:descending+ を指定すると降順にレコードを
 *       取り出す。
 *     @option options :order_by (:key)
 *       +:id+ を指定するとID順にレコードを取り出す。
 *       +:key+ 指定するとキー順にレコードを取り出す。(デフォル
 *       ト)
 *   @macro database.each.options
 *
 * @overload each(options=nil)
 *   @macro database.each.options
 *   @option options :ignore_missing_object (false)
 *     Specify +true+ to ignore missing object. Otherwise, an exception is
 *     raised for missing object.
 *
 *   @since 2.0.5
 */
static VALUE
rb_grn_database_each (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *database;
    grn_table_cursor *cursor;
    VALUE rb_cursor, rb_options, rb_order, rb_order_by;
    VALUE rb_ignore_missing_object;
    int flags = 0;
    grn_id id;
    VALUE exception;

    RETURN_ENUMERATOR(self, argc, argv);

    rb_grn_database_deconstruct(SELF(self), &database, &context,
                                NULL, NULL, NULL, NULL);

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

    rb_grn_scan_options(rb_options,
                        "order", &rb_order,
                        "order_by", &rb_order_by,
                        "ignore_missing_object", &rb_ignore_missing_object,
                        NULL);

    flags |= rb_grn_table_cursor_order_to_flag(rb_order);
    flags |= rb_grn_table_cursor_order_by_to_flag(GRN_TABLE_PAT_KEY,
                                                  self,
                                                  rb_order_by);

    cursor = grn_table_cursor_open(context, database, NULL, 0, NULL, 0,
                                   0, -1,
                                   flags);
    rb_cursor = GRNTABLECURSOR2RVAL(Qnil, context, cursor);
    rb_iv_set(self, "cursor", rb_cursor);
    while ((id = grn_table_cursor_next(context, cursor)) != GRN_ID_NIL) {
        grn_obj *object;

        object = grn_ctx_at(context, id);
        if (!object && RTEST(rb_ignore_missing_object)) {
            context->rc = GRN_SUCCESS;
            continue;
        }

        exception = rb_grn_context_to_exception(context, self);
        if (!NIL_P(exception)) {
            rb_grn_object_close(rb_cursor);
            rb_iv_set(self, "cursor", Qnil);
            rb_exc_raise(exception);
        }

        if (object) {
            rb_yield(GRNOBJECT2RVAL(Qnil, context, object, GRN_FALSE));
        }
    }
    rb_grn_object_close(rb_cursor);
    rb_iv_set(self, "cursor", Qnil);

    return Qnil;
}
Esempio n. 3
0
void
rb_grn_context_check (grn_ctx *context, VALUE related_object)
{
    VALUE exception;

    exception = rb_grn_context_to_exception(context, related_object);
    if (NIL_P(exception))
	return;

    rb_exc_raise(exception);
}
Esempio n. 4
0
/*
 * インデックス対象となっている {Groonga::Column} の配列を返す。
 *
 * @overload sources
 *   @return [::Array<Groonga::Column>]
 */
static VALUE
rb_grn_index_column_get_sources (VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *column;
    grn_obj sources;
    grn_id *source_ids;
    VALUE rb_sources;
    int i, n;
    VALUE exception;

    rb_grn_index_column_deconstruct(SELF(self), &column, &context,
                                    NULL, NULL,
                                    NULL, NULL, NULL, NULL,
                                    NULL, NULL);

    GRN_OBJ_INIT(&sources, GRN_BULK, 0, GRN_ID_NIL);
    grn_obj_get_info(context, column, GRN_INFO_SOURCE, &sources);
    rb_grn_context_check(context, self);

    n = GRN_BULK_VSIZE(&sources) / sizeof(grn_id);
    source_ids = (grn_id *)GRN_BULK_HEAD(&sources);
    rb_sources = rb_ary_new2(n);
    for (i = 0; i < n; i++) {
        grn_obj *source;
        VALUE rb_source;

        source = grn_ctx_at(context, *source_ids);
        exception = rb_grn_context_to_exception(context, self);
        if (!NIL_P(exception)) {
            grn_obj_unlink(context, &sources);
            rb_exc_raise(exception);
        }

        rb_source = GRNOBJECT2RVAL(Qnil, context, source, GRN_FALSE);
        rb_ary_push(rb_sources, rb_source);
        source_ids++;
    }
    grn_obj_unlink(context, &sources);

    return rb_sources;
}
Esempio n. 5
0
/*
 * インデックス対象となる複数のカラムを配列で設定する。
 *
 * @overload sources=(columns)
 *   @param [::Array<Groonga::Column>] columns インデックス対象となるカラムの配列
 */
static VALUE
rb_grn_index_column_set_sources (VALUE self, VALUE rb_sources)
{
    VALUE exception;
    grn_ctx *context = NULL;
    grn_obj *column;
    int i, n;
    VALUE *rb_source_values;
    grn_id range_id;
    grn_id *sources;
    grn_rc rc;

    rb_grn_index_column_deconstruct(SELF(self), &column, &context,
                                    NULL, NULL,
                                    NULL, NULL,
                                    &range_id, NULL,
                                    NULL, NULL);

    n = RARRAY_LEN(rb_sources);
    rb_source_values = RARRAY_PTR(rb_sources);
    sources = ALLOCA_N(grn_id, n);
    for (i = 0; i < n; i++) {
        sources[i] = resolve_source_id(context, column, range_id,
                                       rb_source_values[i]);
    }

    {
        grn_obj bulk_sources;
        GRN_OBJ_INIT(&bulk_sources, GRN_BULK, 0, GRN_ID_NIL);
        GRN_TEXT_SET(context, &bulk_sources, sources, n * sizeof(grn_id));
        rc = grn_obj_set_info(context, column, GRN_INFO_SOURCE, &bulk_sources);
        exception = rb_grn_context_to_exception(context, self);
        grn_obj_unlink(context, &bulk_sources);
    }

    if (!NIL_P(exception))
        rb_exc_raise(exception);
    rb_grn_rc_check(rc, self);

    return Qnil;
}
Esempio n. 6
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;
}
Esempio n. 7
0
/*
 * 文字列 _query_ をパースする。
 * @overload parse(query, options={})
 *   @param [String] query パースする文字列
 *   @param [::Hash] options The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :default_column
 *     "column_name:hoge"ではなく"hoge"のようにcolumn_nameが指
 *     定されない条件の検索対象となるカラムを指定する。
 *   @option options :default_operator (Groonga::Operator::AND)
 *     "+"や"OR"で繋がれず、ただ列挙された複数の条件があった時、
 *     _expression_ 全体として各レコードをヒットとみなすかの論理
 *     条件を指定する。省略した場合はGroonga::Operator::AND。
 *
 *     - Groonga::Operator::OR :=
 *       レコードはいずれかの条件にマッチすればいい。 =:
 *     - Groonga::Operator::AND :=
 *       レコードは全ての条件にマッチしなければならない。 =:
 *     - Groonga::Operator::AND_NOT :=
 *       最初の条件にレコードはマッチし、残りの条件にレコードは
 *       マッチしてはならない。 =:
 *
 *   @option options :default_mode (Groonga::Operator::MATCH)
 *     検索時のモードを指定する。省略した場合はGroonga::Operator::MATCH。
 *     (FIXME: モードによってどういう動作になるかを書く。)
 *   @option options :syntax (:query)
 *     _query_ の構文を指定する。指定可能な値は以下の通り。省略
 *     した場合は +:query+ 。
 *
 *     - +:query+ :=
 *       「文字列1 OR 文字列2」で「"文字列1"あるいは"文字列2"
 *       にマッチという検索エンジンで利用できるような構文を使
 *       う。
 *       参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html =:
 *     - +nil+ :=
 *       +:query+と同様 =:
 *     - +:script+ :=
 *       「[カラム名] == [値]」というようにECMAScript風の構文を使う。
 *       参考: "Groongaのscript構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/script_syntax.html =:
 *   @option options :allow_pragma
 *     _query_ の構文に query を用いているとき( +:syntax+
 *     オプション参照)、「*E-1」というようにクエリの先頭で
 *     pragmaを利用できるようにする。script構文を用いている
 *     ときはこのオプションを利用できない。
 *
 *     デフォルトではプラグマを利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 *   @option options :allow_column
 *     _query_ の構文にqueryを用いているとき( +:syntax+ オプショ
 *     ン参照)、「カラム名:値」というようにカラム名を指定した
 *     条件式を利用できるようにする。script構文を用いていると
 *     きはこのオプションを利用できない。
 *
 *     デフォルトではカラム名を指定した条件式を利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 *   @option options :allow_update
 *     _query_ の構文にscriptを用いているとき( +:syntax+ オプショ
 *     ン参照)、「カラム名 = 値」というように更新操作を利用で
 *     きるようにする。query構文を用いているときはこのオプショ
 *     ンを利用できない。
 *
 *     デフォルトでは更新操作を利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 */
static VALUE
rb_grn_expression_parse (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *expression, *default_column;
    grn_bool default_column_is_created = GRN_FALSE;
    grn_operator default_operator = GRN_OP_AND;
    grn_operator default_mode = GRN_OP_MATCH;
    grn_rc rc;
    char *query = NULL;
    unsigned query_size = 0;
    grn_expr_flags flags = 0;
    VALUE options, rb_query, rb_default_column, rb_default_operator;
    VALUE rb_default_mode, rb_syntax;
    VALUE rb_allow_pragma, rb_allow_column, rb_allow_update, rb_allow_leading_not;
    VALUE exception = Qnil;

    rb_scan_args(argc, argv, "11", &rb_query, &options);
    rb_grn_scan_options(options,
                        "default_column", &rb_default_column,
                        "default_operator", &rb_default_operator,
                        "default_mode", &rb_default_mode,
                        "syntax", &rb_syntax,
                        "allow_pragma", &rb_allow_pragma,
                        "allow_column", &rb_allow_column,
                        "allow_update", &rb_allow_update,
                        "allow_leading_not", &rb_allow_leading_not,
                        NULL);

    query = StringValuePtr(rb_query);
    query_size = RSTRING_LEN(rb_query);

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL,
                                  NULL, NULL, NULL);

    if (NIL_P(rb_default_column)) {
        default_column = NULL;
    } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_default_column, rb_cGrnObject))) {
        default_column = RVAL2GRNOBJECT(rb_default_column, &context);
    } else {
        default_column = RVAL2GRNBULK(rb_default_column, context, NULL);
        default_column_is_created = GRN_TRUE;
    }

    if (!NIL_P(rb_default_mode))
        default_mode = RVAL2GRNOPERATOR(rb_default_mode);
    if (!NIL_P(rb_default_operator))
        default_operator = RVAL2GRNSETOPERATOR(rb_default_operator);

    if (NIL_P(rb_syntax) ||
        rb_grn_equal_option(rb_syntax, "query")) {
        flags = GRN_EXPR_SYNTAX_QUERY;
    } else if (rb_grn_equal_option(rb_syntax, "script")) {
        flags = GRN_EXPR_SYNTAX_SCRIPT;
    } else {
        rb_raise(rb_eArgError,
                 "syntax should be one of "
                 "[nil, :query, :script]: %s",
                 rb_grn_inspect(rb_syntax));
    }

    if (NIL_P(rb_allow_pragma)) {
        if (!(flags & GRN_EXPR_SYNTAX_SCRIPT))
            flags |= GRN_EXPR_ALLOW_PRAGMA;
    } else {
        if ((flags & GRN_EXPR_SYNTAX_SCRIPT))
            rb_raise(rb_eArgError,
                     ":allow_pragma isn't allowed in script syntax");
        if (RVAL2CBOOL(rb_allow_pragma))
            flags |= GRN_EXPR_ALLOW_PRAGMA;
    }

    if (NIL_P(rb_allow_column)) {
        if (!(flags & GRN_EXPR_SYNTAX_SCRIPT))
            flags |= GRN_EXPR_ALLOW_COLUMN;
    } else {
        if ((flags & GRN_EXPR_SYNTAX_SCRIPT))
            rb_raise(rb_eArgError,
                     ":allow_column isn't allowed in script syntax");
        if (RVAL2CBOOL(rb_allow_column))
            flags |= GRN_EXPR_ALLOW_COLUMN;
    }

    if (NIL_P(rb_allow_update)) {
        flags |= GRN_EXPR_ALLOW_UPDATE;
    } else {
        if (RVAL2CBOOL(rb_allow_update))
            flags |= GRN_EXPR_ALLOW_UPDATE;
    }

    if (!NIL_P(rb_allow_leading_not)) {
        if (RVAL2CBOOL(rb_allow_leading_not))
            flags |= GRN_EXPR_ALLOW_LEADING_NOT;
    }

    rc = grn_expr_parse(context, expression, query, query_size,
                        default_column, default_mode, default_operator,
                        flags);
    if (rc != GRN_SUCCESS) {
        VALUE related_object;

        related_object =
            rb_ary_new_from_args(2,
                                 self,
                                 rb_ary_new_from_values(argc, argv));
        exception = rb_grn_context_to_exception(context, related_object);
    }
    if (default_column_is_created)
        grn_obj_unlink(context, default_column);

    if (!NIL_P(exception))
        rb_exc_raise(exception);

    return Qnil;
}