groonga 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/NEWS.ja.rdoc +18 -3
  2. data/NEWS.rdoc +18 -3
  3. data/README.ja.rdoc +2 -0
  4. data/README.rdoc +2 -0
  5. data/Rakefile +14 -5
  6. data/TUTORIAL.ja.rdoc +82 -16
  7. data/benchmark/{read-write-small-many-items.rb → read-write-many-small-items.rb} +26 -23
  8. data/benchmark/{write-small-many-items.rb → write-many-small-items.rb} +26 -23
  9. data/example/bookmark.rb +49 -5
  10. data/ext/rb-grn-array.c +11 -1
  11. data/ext/rb-grn-column.c +132 -5
  12. data/ext/rb-grn-context.c +85 -80
  13. data/ext/rb-grn-database.c +182 -9
  14. data/ext/rb-grn-expression-builder.c +69 -0
  15. data/ext/rb-grn-expression.c +314 -0
  16. data/ext/rb-grn-fix-size-column.c +68 -89
  17. data/ext/rb-grn-hash.c +14 -5
  18. data/ext/rb-grn-index-column.c +14 -55
  19. data/ext/rb-grn-object.c +206 -75
  20. data/ext/rb-grn-operation.c +92 -0
  21. data/ext/rb-grn-patricia-trie.c +10 -32
  22. data/ext/rb-grn-query.c +9 -9
  23. data/ext/rb-grn-table-cursor.c +19 -80
  24. data/ext/rb-grn-table-key-support.c +33 -39
  25. data/ext/rb-grn-table.c +436 -79
  26. data/ext/rb-grn-type.c +10 -3
  27. data/ext/rb-grn-utils.c +131 -4
  28. data/ext/rb-grn-variable-size-column.c +36 -0
  29. data/ext/rb-grn-variable.c +90 -0
  30. data/ext/rb-grn.h +109 -56
  31. data/ext/rb-groonga.c +4 -0
  32. data/extconf.rb +39 -13
  33. data/html/index.html +2 -2
  34. data/lib/groonga.rb +22 -0
  35. data/lib/groonga/expression-builder.rb +141 -0
  36. data/lib/groonga/record.rb +25 -1
  37. data/lib/groonga/schema.rb +418 -0
  38. data/test/test-column.rb +11 -23
  39. data/test/test-context.rb +1 -1
  40. data/test/test-database.rb +60 -19
  41. data/test/test-expression-builder.rb +114 -0
  42. data/test/test-expression.rb +55 -0
  43. data/test/test-fix-size-column.rb +53 -0
  44. data/test/test-hash.rb +10 -3
  45. data/test/test-index-column.rb +24 -0
  46. data/test/test-patricia-trie.rb +9 -0
  47. data/test/test-procedure.rb +5 -5
  48. data/test/test-record.rb +71 -4
  49. data/test/test-schema.rb +207 -0
  50. data/test/test-table.rb +94 -12
  51. data/test/test-type.rb +18 -11
  52. data/test/test-variable-size-column.rb +53 -0
  53. data/test/test-variable.rb +28 -0
  54. metadata +18 -5
data/ext/rb-grn-table.c CHANGED
@@ -36,67 +36,29 @@ VALUE
36
36
  rb_grn_table_to_ruby_object (grn_ctx *context, grn_obj *table,
37
37
  rb_grn_boolean owner)
38
38
  {
39
- return GRNOBJECT2RVAL(rb_cGrnTable, context, table, owner);
39
+ return GRNOBJECT2RVAL(Qnil, context, table, owner);
40
40
  }
41
41
 
42
42
  void
43
- rb_grn_table_unbind (RbGrnTable *rb_grn_table)
43
+ rb_grn_table_finalizer (grn_ctx *context, grn_obj *object,
44
+ RbGrnTable *rb_grn_table)
44
45
  {
45
- RbGrnObject *rb_grn_object;
46
- grn_ctx *context;
47
-
48
- rb_grn_object = RB_GRN_OBJECT(rb_grn_table);
49
- context = rb_grn_object->context;
50
-
51
- if (context)
46
+ if (context && rb_grn_table->value)
52
47
  grn_obj_close(context, rb_grn_table->value);
53
-
54
- rb_grn_object_unbind(rb_grn_object);
55
- }
56
-
57
- static void
58
- rb_grn_table_free (void *object)
59
- {
60
- RbGrnTable *rb_grn_table = object;
61
-
62
- rb_grn_table_unbind(rb_grn_table);
63
- xfree(rb_grn_table);
64
- }
65
-
66
- VALUE
67
- rb_grn_table_alloc (VALUE klass)
68
- {
69
- return Data_Wrap_Struct(klass, NULL, rb_grn_table_free, NULL);
48
+ rb_grn_table->value = NULL;
70
49
  }
71
50
 
72
51
  void
73
52
  rb_grn_table_bind (RbGrnTable *rb_grn_table,
74
- grn_ctx *context, grn_obj *table, rb_grn_boolean owner)
53
+ grn_ctx *context, grn_obj *table)
75
54
  {
76
55
  RbGrnObject *rb_grn_object;
77
56
 
78
57
  rb_grn_object = RB_GRN_OBJECT(rb_grn_table);
79
- rb_grn_object_bind(rb_grn_object, context, table, owner);
80
- rb_grn_object->unbind = RB_GRN_UNBIND_FUNCTION(rb_grn_table_unbind);
81
-
82
58
  rb_grn_table->value = grn_obj_open(context, GRN_BULK, 0,
83
59
  rb_grn_object->range_id);
84
60
  }
85
61
 
86
- void
87
- rb_grn_table_assign (VALUE self, VALUE rb_context,
88
- grn_ctx *context, grn_obj *table,
89
- rb_grn_boolean owner)
90
- {
91
- RbGrnTable *rb_grn_table;
92
-
93
- rb_grn_table = ALLOC(RbGrnTable);
94
- DATA_PTR(self) = rb_grn_table;
95
- rb_grn_table_bind(rb_grn_table, context, table, owner);
96
-
97
- rb_iv_set(self, "context", rb_context);
98
- }
99
-
100
62
  void
101
63
  rb_grn_table_deconstruct (RbGrnTable *rb_grn_table,
102
64
  grn_obj **table,
@@ -118,6 +80,57 @@ rb_grn_table_deconstruct (RbGrnTable *rb_grn_table,
118
80
  *value = rb_grn_table->value;
119
81
  }
120
82
 
83
+ static void
84
+ rb_grn_table_mark (void *data)
85
+ {
86
+ RbGrnObject *rb_grn_object = data;
87
+ grn_ctx *context;
88
+ grn_obj *table;
89
+ grn_obj *column_ids;
90
+ int n;
91
+ grn_table_cursor *cursor;
92
+
93
+ context = rb_grn_object->context;
94
+ table = rb_grn_object->object;
95
+ if (!context || !table)
96
+ return;
97
+
98
+ if (!grn_obj_path(context, table))
99
+ return;
100
+
101
+ column_ids = grn_table_create(context, NULL, 0, NULL,
102
+ GRN_TABLE_HASH_KEY, NULL, 0);
103
+ n = grn_table_columns(context, table, NULL, 0, column_ids);
104
+ if (n == 0) {
105
+ grn_obj_close(context, column_ids);
106
+ return;
107
+ }
108
+
109
+ cursor = grn_table_cursor_open(context, column_ids, NULL, 0, NULL, 0,
110
+ GRN_CURSOR_ASCENDING);
111
+ while (grn_table_cursor_next(context, cursor) != GRN_ID_NIL) {
112
+ void *key;
113
+ grn_id *column_id;
114
+ grn_obj *column;
115
+ RbGrnObject *rb_grn_column;
116
+
117
+ grn_table_cursor_get_key(context, cursor, &key);
118
+ column_id = key;
119
+ column = grn_ctx_at(context, *column_id);
120
+ rb_grn_column = grn_obj_user_data(context, column)->ptr;
121
+ if (rb_grn_column)
122
+ rb_gc_mark(rb_grn_column->self);
123
+ }
124
+ grn_table_cursor_close(context, cursor);
125
+ grn_obj_close(context, column_ids);
126
+ }
127
+
128
+ static VALUE
129
+ rb_grn_table_alloc (VALUE klass)
130
+ {
131
+ return Data_Wrap_Struct(klass, rb_grn_table_mark, rb_grn_object_free, NULL);
132
+ }
133
+
121
134
  VALUE
122
135
  rb_grn_table_s_create (int argc, VALUE *argv, VALUE klass,
123
136
  grn_obj_flags key_store)
@@ -150,6 +163,7 @@ rb_grn_table_s_create (int argc, VALUE *argv, VALUE klass,
150
163
  if (!NIL_P(rb_name)) {
151
164
  name = StringValuePtr(rb_name);
152
165
  name_size = RSTRING_LEN(rb_name);
166
+ flags |= GRN_OBJ_PERSISTENT;
153
167
  }
154
168
 
155
169
  if (!NIL_P(rb_path)) {
@@ -177,7 +191,7 @@ rb_grn_table_s_create (int argc, VALUE *argv, VALUE klass,
177
191
 
178
192
  table = grn_table_create(context, name, name_size, path,
179
193
  flags, key_type, value_size);
180
- rb_table = rb_grn_table_alloc(klass);
194
+ rb_table = rb_grn_object_alloc(klass);
181
195
  rb_grn_table_assign(rb_table, rb_context, context, table, RB_GRN_TRUE);
182
196
  rb_grn_context_check(context, rb_table);
183
197
 
@@ -226,13 +240,7 @@ rb_grn_table_initialize (int argc, VALUE *argv, VALUE self)
226
240
  VALUE rb_context;
227
241
 
228
242
  table = rb_grn_table_open_raw(argc, argv, &context, &rb_context);
229
- /* FIXME!!!! */
230
- if (self == rb_cGrnArray) {
231
- rb_grn_table_assign(self, rb_context, context, table, RB_GRN_TRUE);
232
- } else {
233
- rb_grn_table_key_support_assign(self, rb_context, context,
234
- table, RB_GRN_TRUE);
235
- }
243
+ rb_grn_object_assign(Qnil, self, rb_context, context, table);
236
244
  rb_grn_context_check(context, self);
237
245
 
238
246
  return Qnil;
@@ -241,7 +249,8 @@ rb_grn_table_initialize (int argc, VALUE *argv, VALUE self)
241
249
  static VALUE
242
250
  rb_grn_table_s_open (int argc, VALUE *argv, VALUE klass)
243
251
  {
244
- VALUE rb_table;
252
+ grn_user_data *user_data;
253
+ VALUE rb_table = Qnil;
245
254
  grn_obj *table;
246
255
  grn_ctx *context = NULL;
247
256
  VALUE rb_context;
@@ -255,28 +264,26 @@ rb_grn_table_s_open (int argc, VALUE *argv, VALUE klass)
255
264
  rb_grn_inspect(klass),
256
265
  rb_grn_inspect(rb_ary_new4(argc, argv)));
257
266
 
258
- if (klass == rb_cGrnTable) {
259
- klass = GRNOBJECT2RCLASS(table);
267
+ user_data = grn_obj_user_data(context, table);
268
+ if (user_data && user_data->ptr) {
269
+ rb_table = RB_GRN_OBJECT(user_data->ptr)->self;
260
270
  } else {
261
- VALUE rb_class;
262
-
263
- rb_class = GRNOBJECT2RCLASS(table);
264
- if (rb_class != klass) {
265
- rb_raise(rb_eTypeError,
266
- "unexpected existing table type: %s: expected %s",
267
- rb_grn_inspect(rb_class),
268
- rb_grn_inspect(klass));
271
+ if (klass == rb_cGrnTable) {
272
+ klass = GRNOBJECT2RCLASS(table);
273
+ } else {
274
+ VALUE rb_class;
275
+
276
+ rb_class = GRNOBJECT2RCLASS(table);
277
+ if (rb_class != klass) {
278
+ rb_raise(rb_eTypeError,
279
+ "unexpected existing table type: %s: expected %s",
280
+ rb_grn_inspect(rb_class),
281
+ rb_grn_inspect(klass));
282
+ }
269
283
  }
270
- }
271
284
 
272
- /* FIXME!!!! */
273
- if (klass == rb_cGrnArray) {
274
- rb_table = rb_grn_table_alloc(klass);
275
- rb_grn_table_assign(rb_table, rb_context, context, table, RB_GRN_TRUE);
276
- } else {
277
- rb_table = rb_grn_table_key_support_alloc(klass);
278
- rb_grn_table_key_support_assign(rb_table, rb_context, context,
279
- table, RB_GRN_TRUE);
285
+ rb_table = rb_grn_object_alloc(klass);
286
+ rb_grn_object_assign(klass, rb_table, rb_context, context, table);
280
287
  }
281
288
 
282
289
  if (rb_block_given_p())
@@ -791,20 +798,23 @@ rb_grn_table_sort (int argc, VALUE *argv, VALUE self)
791
798
  grn_obj *table;
792
799
  grn_obj *result;
793
800
  grn_table_sort_key *keys;
794
- int n_records, limit = 0;
795
801
  int i, n_keys;
802
+ int n_records, limit = 0;
796
803
  VALUE rb_keys, options;
797
804
  VALUE rb_limit;
798
805
  VALUE *rb_sort_keys;
806
+ grn_table_cursor *cursor;
807
+ VALUE rb_result;
799
808
 
800
809
  rb_grn_table_deconstruct(SELF(self), &table, &context,
801
810
  NULL, NULL,
802
811
  NULL, NULL, NULL);
803
812
 
804
813
  rb_scan_args(argc, argv, "11", &rb_keys, &options);
805
- rb_grn_scan_options(options,
806
- "limit", &rb_limit,
807
- NULL);
814
+
815
+ if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_keys, rb_cArray)))
816
+ rb_raise(rb_eArgError, "keys should be an array of key: <%s>",
817
+ rb_grn_inspect(rb_keys));
808
818
 
809
819
  n_keys = RARRAY_LEN(rb_keys);
810
820
  rb_sort_keys = RARRAY_PTR(rb_keys);
@@ -838,15 +848,113 @@ rb_grn_table_sort (int argc, VALUE *argv, VALUE self)
838
848
  }
839
849
  }
840
850
 
851
+ rb_grn_scan_options(options,
852
+ "limit", &rb_limit,
853
+ NULL);
854
+
841
855
  if (!NIL_P(rb_limit))
842
856
  limit = NUM2INT(rb_limit);
843
857
 
844
858
  result = grn_table_create(context, NULL, 0, NULL, GRN_TABLE_NO_KEY,
845
859
  table, sizeof(grn_id));
846
- n_records = grn_table_sort(context, table, limit,
847
- result, keys, n_keys);
860
+ n_records = grn_table_sort(context, table, limit, result, keys, n_keys);
848
861
 
849
- return GRNOBJECT2RVAL(Qnil, context, result, RB_GRN_TRUE);
862
+ rb_result = rb_ary_new();
863
+ cursor = grn_table_cursor_open(context, result, NULL, 0, NULL, 0,
864
+ GRN_CURSOR_ASCENDING);
865
+ while (grn_table_cursor_next(context, cursor) != GRN_ID_NIL) {
866
+ void *value;
867
+ grn_id *id;
868
+
869
+ grn_table_cursor_get_value(context, cursor, &value);
870
+ id = value;
871
+ rb_ary_push(rb_result, rb_grn_record_new(self, *id, Qnil));
872
+ }
873
+ grn_table_cursor_close(context, cursor);
874
+ grn_obj_close(context, result);
875
+
876
+ rb_grn_context_check(context, self); /* FIXME: here is too late */
877
+
878
+ return rb_result;
879
+ }
880
+
881
+ static VALUE
882
+ rb_grn_table_group (int argc, VALUE *argv, VALUE self)
883
+ {
884
+ grn_ctx *context = NULL;
885
+ grn_obj *table;
886
+ grn_table_sort_key *keys;
887
+ grn_table_group_result *results;
888
+ int i, n_keys, n_results;
889
+ grn_rc rc;
890
+ VALUE rb_keys;
891
+ VALUE *rb_sort_keys;
892
+ VALUE rb_results;
893
+
894
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
895
+ NULL, NULL,
896
+ NULL, NULL, NULL);
897
+
898
+ rb_scan_args(argc, argv, "10", &rb_keys);
899
+
900
+ if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_keys, rb_cArray)))
901
+ rb_raise(rb_eArgError, "keys should be an array of key: <%s>",
902
+ rb_grn_inspect(rb_keys));
903
+
904
+ n_keys = RARRAY_LEN(rb_keys);
905
+ rb_sort_keys = RARRAY_PTR(rb_keys);
906
+ keys = ALLOCA_N(grn_table_sort_key, n_keys);
907
+ for (i = 0; i < n_keys; i++) {
908
+ VALUE rb_sort_options, rb_key;
909
+
910
+ if (RVAL2CBOOL(rb_obj_is_kind_of(rb_sort_keys[i], rb_cHash))) {
911
+ rb_sort_options = rb_sort_keys[i];
912
+ } else {
913
+ rb_sort_options = rb_hash_new();
914
+ rb_hash_aset(rb_sort_options,
915
+ RB_GRN_INTERN("key"),
916
+ rb_sort_keys[i]);
917
+ }
918
+ rb_grn_scan_options(rb_sort_options,
919
+ "key", &rb_key,
920
+ NULL);
921
+ if (RVAL2CBOOL(rb_obj_is_kind_of(rb_key, rb_cString)))
922
+ rb_key = rb_grn_table_get_column(self, rb_key);
923
+ keys[i].key = RVAL2GRNOBJECT(rb_key, &context);
924
+ keys[i].flags = 0;
925
+ }
926
+
927
+ n_results = n_keys;
928
+ results = ALLOCA_N(grn_table_group_result, n_results);
929
+ rb_results = rb_ary_new();
930
+ for (i = 0; i < n_results; i++) {
931
+ grn_obj *result;
932
+ grn_id range_id;
933
+ VALUE rb_result;
934
+
935
+ range_id = grn_obj_get_range(context, keys[i].key);
936
+ result = grn_table_create(context, NULL, 0, NULL,
937
+ GRN_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
938
+ grn_ctx_at(context, range_id), 0);
939
+ results[i].table = result;
940
+ results[i].key_begin = 0;
941
+ results[i].key_end = 0;
942
+ results[i].limit = 0;
943
+ results[i].flags = 0;
944
+ results[i].op = GRN_OP_OR;
945
+
946
+ rb_result = GRNOBJECT2RVAL(Qnil, context, result, RB_GRN_TRUE);
947
+ rb_ary_push(rb_results, rb_result);
948
+ }
949
+
950
+ rc = grn_table_group(context, table, keys, n_keys, results, n_results);
951
+ rb_grn_context_check(context, self);
952
+ rb_grn_rc_check(rc, self);
953
+
954
+ if (n_results == 1)
955
+ return rb_ary_pop(rb_results);
956
+ else
957
+ return rb_results;
850
958
  }
851
959
 
852
960
  /*
@@ -914,6 +1022,247 @@ rb_grn_table_array_set (VALUE self, VALUE rb_id, VALUE rb_value)
914
1022
  return Qnil;
915
1023
  }
916
1024
 
1025
+ /*
1026
+ * Document-method: unlock
1027
+ *
1028
+ * call-seq:
1029
+ * table.unlock(options={})
1030
+ *
1031
+ * _table_のロックを解除する。
1032
+ *
1033
+ * 利用可能なオプションは以下の通り。
1034
+ *
1035
+ * [_:id_]
1036
+ * _:id_で指定したレコードのロックを解除する。(注:
1037
+ * groonga側が未実装のため、現在は無視される)
1038
+ */
1039
+ static VALUE
1040
+ rb_grn_table_unlock (int argc, VALUE *argv, VALUE self)
1041
+ {
1042
+ grn_id id = GRN_ID_NIL;
1043
+ grn_ctx *context;
1044
+ grn_obj *table;
1045
+ grn_rc rc;
1046
+ VALUE options, rb_id;
1047
+
1048
+ rb_scan_args(argc, argv, "01", &options);
1049
+
1050
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1051
+ NULL, NULL,
1052
+ NULL, NULL, NULL);
1053
+
1054
+ rb_grn_scan_options(options,
1055
+ "id", &rb_id,
1056
+ NULL);
1057
+
1058
+ if (!NIL_P(rb_id))
1059
+ id = NUM2UINT(rb_id);
1060
+
1061
+ rc = grn_obj_unlock(context, table, id);
1062
+ rb_grn_context_check(context, self);
1063
+ rb_grn_rc_check(rc, self);
1064
+
1065
+ return Qnil;
1066
+ }
1067
+
1068
+ static VALUE
1069
+ rb_grn_table_unlock_ensure (VALUE self)
1070
+ {
1071
+ return rb_grn_table_unlock(0, NULL, self);
1072
+ }
1073
+
1074
+ /*
1075
+ * Document-method: lock
1076
+ *
1077
+ * call-seq:
1078
+ * table.lock(options={})
1079
+ * table.lock(options={}) {...}
1080
+ *
1081
+ * _table_をロックする。ロックに失敗した場合は
1082
+ * Groonga::ResourceDeadlockAvoided例外が発生する。
1083
+ *
1084
+ * ブロックを指定した場合はブロックを抜けたときにunlockする。
1085
+ *
1086
+ * 利用可能なオプションは以下の通り。
1087
+ *
1088
+ * [_:timeout_]
1089
+ * ロックを獲得できなかった場合は_:timeout_秒間ロックの獲
1090
+ * 得を試みる。_:timeout_秒以内にロックを獲得できなかった
1091
+ * 場合は例外が発生する。
1092
+ * [_:id_]
1093
+ * _:id_で指定したレコードをロックする。(注: groonga側が
1094
+ * 未実装のため、現在は無視される)
1095
+ */
1096
+ static VALUE
1097
+ rb_grn_table_lock (int argc, VALUE *argv, VALUE self)
1098
+ {
1099
+ grn_id id = GRN_ID_NIL;
1100
+ grn_ctx *context;
1101
+ grn_obj *table;
1102
+ int timeout = 0;
1103
+ grn_rc rc;
1104
+ VALUE options, rb_timeout, rb_id;
1105
+
1106
+ rb_scan_args(argc, argv, "01", &options);
1107
+
1108
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1109
+ NULL, NULL,
1110
+ NULL, NULL, NULL);
1111
+
1112
+ rb_grn_scan_options(options,
1113
+ "timeout", &rb_timeout,
1114
+ "id", &rb_id,
1115
+ NULL);
1116
+
1117
+ if (!NIL_P(rb_timeout))
1118
+ timeout = NUM2UINT(rb_timeout);
1119
+
1120
+ if (!NIL_P(rb_id))
1121
+ id = NUM2UINT(rb_id);
1122
+
1123
+ rc = grn_obj_lock(context, table, id, timeout);
1124
+ rb_grn_context_check(context, self);
1125
+ rb_grn_rc_check(rc, self);
1126
+
1127
+ if (rb_block_given_p()) {
1128
+ return rb_ensure(rb_yield, Qnil, rb_grn_table_unlock_ensure, self);
1129
+ } else {
1130
+ return Qnil;
1131
+ }
1132
+ }
1133
+
1134
+ /*
1135
+ * Document-method: clear_lock
1136
+ *
1137
+ * call-seq:
1138
+ * table.clear_lock(options={})
1139
+ *
1140
+ * _table_のロックを強制的に解除する。
1141
+ *
1142
+ * 利用可能なオプションは以下の通り。
1143
+ *
1144
+ * [_:id_]
1145
+ * _:id_で指定したレコードのロックを強制的に解除する。
1146
+ * (注: groonga側が未実装のため、現在は無視される。実装さ
1147
+ * れるのではないかと思っているが、実装されないかもしれな
1148
+ * い。)
1149
+ */
1150
+ static VALUE
1151
+ rb_grn_table_clear_lock (int argc, VALUE *argv, VALUE self)
1152
+ {
1153
+ grn_id id = GRN_ID_NIL;
1154
+ grn_ctx *context;
1155
+ grn_obj *table;
1156
+ VALUE options, rb_id;
1157
+
1158
+ rb_scan_args(argc, argv, "01", &options);
1159
+
1160
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1161
+ NULL, NULL,
1162
+ NULL, NULL, NULL);
1163
+
1164
+ rb_grn_scan_options(options,
1165
+ "id", &rb_id,
1166
+ NULL);
1167
+
1168
+ if (!NIL_P(rb_id))
1169
+ id = NUM2UINT(rb_id);
1170
+
1171
+ grn_obj_clear_lock(context, table);
1172
+
1173
+ return Qnil;
1174
+ }
1175
+
1176
+ /*
1177
+ * Document-method: locked?
1178
+ *
1179
+ * call-seq:
1180
+ * table.locked?(options={})
1181
+ *
1182
+ * _table_がロックされていれば+true+を返す。
1183
+ *
1184
+ * 利用可能なオプションは以下の通り。
1185
+ *
1186
+ * [_:id_]
1187
+ * _:id_で指定したレコードがロックされていれば+true+を返す。
1188
+ * (注: groonga側が未実装のため、現在は無視される。実装さ
1189
+ * れるのではないかと思っているが、実装されないかもしれな
1190
+ * い。)
1191
+ */
1192
+ static VALUE
1193
+ rb_grn_table_is_locked (int argc, VALUE *argv, VALUE self)
1194
+ {
1195
+ grn_id id = GRN_ID_NIL;
1196
+ grn_ctx *context;
1197
+ grn_obj *table;
1198
+ VALUE options, rb_id;
1199
+
1200
+ rb_scan_args(argc, argv, "01", &options);
1201
+
1202
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1203
+ NULL, NULL,
1204
+ NULL, NULL, NULL);
1205
+
1206
+ rb_grn_scan_options(options,
1207
+ "id", &rb_id,
1208
+ NULL);
1209
+
1210
+ if (!NIL_P(rb_id))
1211
+ id = NUM2UINT(rb_id);
1212
+
1213
+ return CBOOL2RVAL(grn_obj_is_locked(context, table));
1214
+ }
1215
+
1216
+ static VALUE
1217
+ rb_grn_table_select (int argc, VALUE *argv, VALUE self)
1218
+ {
1219
+ grn_ctx *context;
1220
+ grn_obj *table, *result, *expression;
1221
+ grn_operator operator = GRN_OP_OR;
1222
+ grn_rc rc;
1223
+ VALUE options;
1224
+ VALUE rb_name, rb_operator, rb_result;
1225
+ VALUE rb_expression, builder;
1226
+
1227
+ rb_scan_args(argc, argv, "01", &options);
1228
+
1229
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1230
+ NULL, NULL,
1231
+ NULL, NULL, NULL);
1232
+
1233
+ rb_grn_scan_options(options,
1234
+ "operator", &rb_operator,
1235
+ "result", &rb_result,
1236
+ "name", &rb_name,
1237
+ NULL);
1238
+
1239
+ if (!NIL_P(rb_operator))
1240
+ operator = NUM2INT(rb_operator);
1241
+
1242
+ if (NIL_P(rb_result)) {
1243
+ result = grn_table_create(context, NULL, 0, NULL,
1244
+ GRN_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
1245
+ table,
1246
+ 0);
1247
+ rb_result = GRNTABLE2RVAL(context, result, RB_GRN_TRUE);
1248
+ } else {
1249
+ result = RVAL2GRNTABLE(rb_result, &context);
1250
+ }
1251
+
1252
+ builder = rb_grn_record_expression_builder_new(self, rb_name);
1253
+ rb_expression = rb_grn_record_expression_builder_build(builder);
1254
+
1255
+ rb_grn_object_deconstruct(RB_GRN_OBJECT(DATA_PTR(rb_expression)),
1256
+ &expression, NULL,
1257
+ NULL, NULL, NULL, NULL);
1258
+
1259
+ rc = grn_table_select(context, table, expression, result, operator);
1260
+ rb_grn_context_check(context, self);
1261
+ rb_grn_rc_check(rc, self);
1262
+
1263
+ return rb_result;
1264
+ }
1265
+
917
1266
  void
918
1267
  rb_grn_init_table (VALUE mGrn)
919
1268
  {
@@ -951,10 +1300,18 @@ rb_grn_init_table (VALUE mGrn)
951
1300
  rb_define_method(rb_cGrnTable, "delete", rb_grn_table_delete, 1);
952
1301
 
953
1302
  rb_define_method(rb_cGrnTable, "sort", rb_grn_table_sort, -1);
1303
+ rb_define_method(rb_cGrnTable, "group", rb_grn_table_group, -1);
954
1304
 
955
1305
  rb_define_method(rb_cGrnTable, "[]", rb_grn_table_array_reference, 1);
956
1306
  rb_define_method(rb_cGrnTable, "[]=", rb_grn_table_array_set, 2);
957
1307
 
1308
+ rb_define_method(rb_cGrnTable, "lock", rb_grn_table_lock, -1);
1309
+ rb_define_method(rb_cGrnTable, "unlock", rb_grn_table_unlock, -1);
1310
+ rb_define_method(rb_cGrnTable, "clear_lock", rb_grn_table_clear_lock, -1);
1311
+ rb_define_method(rb_cGrnTable, "locked?", rb_grn_table_is_locked, -1);
1312
+
1313
+ rb_define_method(rb_cGrnTable, "select", rb_grn_table_select, -1);
1314
+
958
1315
  rb_grn_init_table_key_support(mGrn);
959
1316
  rb_grn_init_array(mGrn);
960
1317
  rb_grn_init_hash(mGrn);