// <cmd> {<len> <column id>} <type> <#keys> [{<len> <key>}]... void hog_del(server_t *s, grn_ctx *ctx) { uint32_t len; receive(s->socket, &len, sizeof(len)); len = ntohl(len); char *buf = malloc(len); receive(s->socket, buf, len); grn_obj *col, *table; col = grn_ctx_get(ctx, buf, len); if(grn_obj_is_table(ctx, col)) table = col; else table = grn_column_table(ctx, col); // get key type char type; receive(s->socket, &type, 1); // submit values for each keys uint32_t nkeys; receive(s->socket, &nkeys, sizeof(nkeys)); nkeys = ntohl(nkeys); for(uint32_t i = 0; i < nkeys; ++i){ receive(s->socket, &len, sizeof(len)); len = ntohl(len); buf = realloc(buf, len); receive(s->socket, buf, len); ntoh_buf(buf, len, type); grn_table_delete(ctx, table, buf, len); } cleanup: free(buf); }
/* * call-seq: * column.table -> Groonga::Table * * カラムが所属するテーブルを返す。 */ static VALUE rb_grn_column_get_table (VALUE self) { grn_ctx *context = NULL; grn_obj *column; grn_obj *table; rb_grn_object_deconstruct((RbGrnObject *)(SELF(self)), &column, &context, NULL, NULL, NULL, NULL); table = grn_column_table(context, column); rb_grn_context_check(context, self); return GRNOBJECT2RVAL(Qnil, context, table, RB_GRN_FALSE); }
// <cmd> {<len> <column id>} <types> <#kvs> [{<len> <key>} {<len> <value>}]... void put_or_set(server_t *s, grn_ctx *ctx, int set) { uint32_t len; HOG_RECV(s, &len, sizeof(len), return); len = ntohl(len); char *buf = hog_alloc(NULL, len); HOG_RECV(s, buf, len, goto cleanup); grn_obj *col, *table; col = grn_ctx_get(ctx, buf, len); if(grn_obj_is_table(ctx, col)) table = col; else table = grn_column_table(ctx, col); // get key and value types char types[2]; HOG_RECV(s, types, 2, goto cleanup); // receive keys and values uint32_t nkeys; HOG_RECV(s, &nkeys, sizeof(nkeys), goto cleanup); nkeys = ntohl(nkeys); grn_obj value; GRN_OBJ_INIT(&value, GRN_BULK, 0, types[1]); for(uint32_t i = 0; i < nkeys; ++i){ HOG_RECV(s, &len, sizeof(len), goto value_fin); len = ntohl(len); buf = hog_alloc(buf, len); HOG_RECV(s, buf, len, goto value_fin); ntoh_buf(buf, len, types[0]); grn_id id; if(set){ id = grn_table_get(ctx, table, buf, len); }else{ id = grn_table_add(ctx, table, buf, len, NULL); } HOG_RECV(s, &len, sizeof(len), goto value_fin); len = ntohl(len); buf = hog_alloc(buf, len); HOG_RECV(s, buf, len, goto value_fin); if(id == GRN_ID_NIL) continue; ntoh_buf(buf, len, types[1]); GRN_BULK_REWIND(&value); grn_bulk_write(ctx, &value, buf, len); grn_obj_set_value(ctx, col, id, &value, GRN_OBJ_SET); } submit_one(s->socket); value_fin: GRN_OBJ_FIN(ctx, &value); cleanup: free(buf); }
/* * 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; }