rroonga 0.9.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. data/AUTHORS +5 -0
  2. data/NEWS.ja.rdoc +114 -0
  3. data/NEWS.rdoc +116 -0
  4. data/README.ja.rdoc +65 -0
  5. data/README.rdoc +66 -0
  6. data/Rakefile +206 -0
  7. data/benchmark/common.rb +49 -0
  8. data/benchmark/read-write-many-small-items.rb +144 -0
  9. data/benchmark/write-many-small-items.rb +135 -0
  10. data/example/bookmark.rb +161 -0
  11. data/example/index-html.rb +89 -0
  12. data/example/search/config.ru +230 -0
  13. data/example/search/public/css/groonga.css +122 -0
  14. data/ext/.gitignore +2 -0
  15. data/ext/groonga/extconf.rb +93 -0
  16. data/ext/groonga/rb-grn-accessor.c +52 -0
  17. data/ext/groonga/rb-grn-array-cursor.c +36 -0
  18. data/ext/groonga/rb-grn-array.c +210 -0
  19. data/ext/groonga/rb-grn-column.c +573 -0
  20. data/ext/groonga/rb-grn-context.c +662 -0
  21. data/ext/groonga/rb-grn-database.c +472 -0
  22. data/ext/groonga/rb-grn-encoding-support.c +64 -0
  23. data/ext/groonga/rb-grn-encoding.c +257 -0
  24. data/ext/groonga/rb-grn-exception.c +1110 -0
  25. data/ext/groonga/rb-grn-expression-builder.c +75 -0
  26. data/ext/groonga/rb-grn-expression.c +731 -0
  27. data/ext/groonga/rb-grn-fix-size-column.c +166 -0
  28. data/ext/groonga/rb-grn-hash-cursor.c +38 -0
  29. data/ext/groonga/rb-grn-hash.c +294 -0
  30. data/ext/groonga/rb-grn-index-column.c +488 -0
  31. data/ext/groonga/rb-grn-logger.c +504 -0
  32. data/ext/groonga/rb-grn-object.c +1369 -0
  33. data/ext/groonga/rb-grn-operation.c +198 -0
  34. data/ext/groonga/rb-grn-patricia-trie-cursor.c +39 -0
  35. data/ext/groonga/rb-grn-patricia-trie.c +488 -0
  36. data/ext/groonga/rb-grn-procedure.c +52 -0
  37. data/ext/groonga/rb-grn-query.c +260 -0
  38. data/ext/groonga/rb-grn-record.c +40 -0
  39. data/ext/groonga/rb-grn-snippet.c +334 -0
  40. data/ext/groonga/rb-grn-table-cursor-key-support.c +69 -0
  41. data/ext/groonga/rb-grn-table-cursor.c +247 -0
  42. data/ext/groonga/rb-grn-table-key-support.c +714 -0
  43. data/ext/groonga/rb-grn-table.c +1977 -0
  44. data/ext/groonga/rb-grn-type.c +181 -0
  45. data/ext/groonga/rb-grn-utils.c +769 -0
  46. data/ext/groonga/rb-grn-variable-size-column.c +36 -0
  47. data/ext/groonga/rb-grn-variable.c +108 -0
  48. data/ext/groonga/rb-grn-view-accessor.c +53 -0
  49. data/ext/groonga/rb-grn-view-cursor.c +35 -0
  50. data/ext/groonga/rb-grn-view-record.c +41 -0
  51. data/ext/groonga/rb-grn-view.c +421 -0
  52. data/ext/groonga/rb-grn.h +698 -0
  53. data/ext/groonga/rb-groonga.c +107 -0
  54. data/extconf.rb +130 -0
  55. data/html/bar.svg +153 -0
  56. data/html/developer.html +117 -0
  57. data/html/developer.svg +469 -0
  58. data/html/download.svg +253 -0
  59. data/html/favicon.ico +0 -0
  60. data/html/favicon.xcf +0 -0
  61. data/html/footer.html.erb +28 -0
  62. data/html/head.html.erb +4 -0
  63. data/html/header.html.erb +17 -0
  64. data/html/index.html +147 -0
  65. data/html/install.svg +636 -0
  66. data/html/logo.xcf +0 -0
  67. data/html/ranguba.css +250 -0
  68. data/html/tutorial.svg +559 -0
  69. data/lib/1.8/groonga.so +0 -0
  70. data/lib/1.9/groonga.so +0 -0
  71. data/lib/groonga.rb +90 -0
  72. data/lib/groonga/context.rb +184 -0
  73. data/lib/groonga/expression-builder.rb +324 -0
  74. data/lib/groonga/patricia-trie.rb +85 -0
  75. data/lib/groonga/record.rb +311 -0
  76. data/lib/groonga/schema.rb +1191 -0
  77. data/lib/groonga/view-record.rb +56 -0
  78. data/license/GPL +340 -0
  79. data/license/LGPL +504 -0
  80. data/license/RUBY +59 -0
  81. data/misc/grnop2ruby.rb +49 -0
  82. data/pkg-config.rb +333 -0
  83. data/rroonga-build.rb +57 -0
  84. data/test-unit/Rakefile +40 -0
  85. data/test-unit/TODO +5 -0
  86. data/test-unit/bin/testrb +5 -0
  87. data/test-unit/html/classic.html +15 -0
  88. data/test-unit/html/index.html +25 -0
  89. data/test-unit/html/index.html.ja +27 -0
  90. data/test-unit/lib/test/unit.rb +323 -0
  91. data/test-unit/lib/test/unit/assertionfailederror.rb +25 -0
  92. data/test-unit/lib/test/unit/assertions.rb +1230 -0
  93. data/test-unit/lib/test/unit/attribute.rb +125 -0
  94. data/test-unit/lib/test/unit/autorunner.rb +360 -0
  95. data/test-unit/lib/test/unit/collector.rb +36 -0
  96. data/test-unit/lib/test/unit/collector/descendant.rb +23 -0
  97. data/test-unit/lib/test/unit/collector/dir.rb +108 -0
  98. data/test-unit/lib/test/unit/collector/load.rb +144 -0
  99. data/test-unit/lib/test/unit/collector/objectspace.rb +34 -0
  100. data/test-unit/lib/test/unit/color-scheme.rb +102 -0
  101. data/test-unit/lib/test/unit/color.rb +96 -0
  102. data/test-unit/lib/test/unit/diff.rb +724 -0
  103. data/test-unit/lib/test/unit/error.rb +130 -0
  104. data/test-unit/lib/test/unit/exceptionhandler.rb +39 -0
  105. data/test-unit/lib/test/unit/failure.rb +136 -0
  106. data/test-unit/lib/test/unit/fixture.rb +176 -0
  107. data/test-unit/lib/test/unit/notification.rb +129 -0
  108. data/test-unit/lib/test/unit/omission.rb +191 -0
  109. data/test-unit/lib/test/unit/pending.rb +150 -0
  110. data/test-unit/lib/test/unit/priority.rb +180 -0
  111. data/test-unit/lib/test/unit/runner/console.rb +52 -0
  112. data/test-unit/lib/test/unit/runner/emacs.rb +8 -0
  113. data/test-unit/lib/test/unit/runner/tap.rb +8 -0
  114. data/test-unit/lib/test/unit/testcase.rb +476 -0
  115. data/test-unit/lib/test/unit/testresult.rb +89 -0
  116. data/test-unit/lib/test/unit/testsuite.rb +110 -0
  117. data/test-unit/lib/test/unit/ui/console/outputlevel.rb +14 -0
  118. data/test-unit/lib/test/unit/ui/console/testrunner.rb +466 -0
  119. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +63 -0
  120. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +92 -0
  121. data/test-unit/lib/test/unit/ui/testrunner.rb +28 -0
  122. data/test-unit/lib/test/unit/ui/testrunnermediator.rb +77 -0
  123. data/test-unit/lib/test/unit/ui/testrunnerutilities.rb +41 -0
  124. data/test-unit/lib/test/unit/util/backtracefilter.rb +41 -0
  125. data/test-unit/lib/test/unit/util/method-owner-finder.rb +28 -0
  126. data/test-unit/lib/test/unit/util/observable.rb +90 -0
  127. data/test-unit/lib/test/unit/util/procwrapper.rb +48 -0
  128. data/test-unit/lib/test/unit/version.rb +7 -0
  129. data/test-unit/sample/adder.rb +13 -0
  130. data/test-unit/sample/subtracter.rb +12 -0
  131. data/test-unit/sample/test_adder.rb +20 -0
  132. data/test-unit/sample/test_subtracter.rb +20 -0
  133. data/test-unit/sample/test_user.rb +23 -0
  134. data/test-unit/test/collector/test-descendant.rb +133 -0
  135. data/test-unit/test/collector/test-load.rb +442 -0
  136. data/test-unit/test/collector/test_dir.rb +406 -0
  137. data/test-unit/test/collector/test_objectspace.rb +100 -0
  138. data/test-unit/test/run-test.rb +15 -0
  139. data/test-unit/test/test-attribute.rb +86 -0
  140. data/test-unit/test/test-color-scheme.rb +67 -0
  141. data/test-unit/test/test-color.rb +47 -0
  142. data/test-unit/test/test-diff.rb +518 -0
  143. data/test-unit/test/test-emacs-runner.rb +60 -0
  144. data/test-unit/test/test-fixture.rb +287 -0
  145. data/test-unit/test/test-notification.rb +33 -0
  146. data/test-unit/test/test-omission.rb +81 -0
  147. data/test-unit/test/test-pending.rb +70 -0
  148. data/test-unit/test/test-priority.rb +119 -0
  149. data/test-unit/test/test-testcase.rb +544 -0
  150. data/test-unit/test/test_assertions.rb +1151 -0
  151. data/test-unit/test/test_error.rb +26 -0
  152. data/test-unit/test/test_failure.rb +33 -0
  153. data/test-unit/test/test_testresult.rb +113 -0
  154. data/test-unit/test/test_testsuite.rb +129 -0
  155. data/test-unit/test/testunit-test-util.rb +14 -0
  156. data/test-unit/test/ui/test_testrunmediator.rb +20 -0
  157. data/test-unit/test/util/test-method-owner-finder.rb +38 -0
  158. data/test-unit/test/util/test_backtracefilter.rb +41 -0
  159. data/test-unit/test/util/test_observable.rb +102 -0
  160. data/test-unit/test/util/test_procwrapper.rb +36 -0
  161. data/test/.gitignore +1 -0
  162. data/test/groonga-test-utils.rb +134 -0
  163. data/test/run-test.rb +58 -0
  164. data/test/test-array.rb +90 -0
  165. data/test/test-column.rb +316 -0
  166. data/test/test-context-select.rb +93 -0
  167. data/test/test-context.rb +73 -0
  168. data/test/test-database.rb +113 -0
  169. data/test/test-encoding.rb +33 -0
  170. data/test/test-exception.rb +93 -0
  171. data/test/test-expression-builder.rb +217 -0
  172. data/test/test-expression.rb +134 -0
  173. data/test/test-fix-size-column.rb +65 -0
  174. data/test/test-gqtp.rb +72 -0
  175. data/test/test-hash.rb +305 -0
  176. data/test/test-index-column.rb +81 -0
  177. data/test/test-logger.rb +37 -0
  178. data/test/test-patricia-trie.rb +205 -0
  179. data/test/test-procedure.rb +37 -0
  180. data/test/test-query.rb +22 -0
  181. data/test/test-record.rb +243 -0
  182. data/test/test-remote.rb +54 -0
  183. data/test/test-schema-view.rb +90 -0
  184. data/test/test-schema.rb +459 -0
  185. data/test/test-snippet.rb +130 -0
  186. data/test/test-table-cursor.rb +153 -0
  187. data/test/test-table-offset-and-limit.rb +102 -0
  188. data/test/test-table-select-normalize.rb +53 -0
  189. data/test/test-table-select.rb +150 -0
  190. data/test/test-table.rb +594 -0
  191. data/test/test-type.rb +71 -0
  192. data/test/test-variable-size-column.rb +98 -0
  193. data/test/test-variable.rb +28 -0
  194. data/test/test-vector-column.rb +76 -0
  195. data/test/test-version.rb +31 -0
  196. data/test/test-view.rb +72 -0
  197. data/text/TUTORIAL.ja.rdoc +392 -0
  198. data/text/expression.rdoc +284 -0
  199. metadata +276 -0
@@ -0,0 +1,1977 @@
1
+ /* -*- c-file-style: "ruby" -*- */
2
+ /*
3
+ Copyright (C) 2009-2010 Kouhei Sutou <kou@clear-code.com>
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License version 2.1 as published by the Free Software Foundation.
8
+
9
+ This library is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ Lesser General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Lesser General Public
15
+ License along with this library; if not, write to the Free Software
16
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ */
18
+
19
+ #include "rb-grn.h"
20
+
21
+ grn_obj *grn_table_open(grn_ctx *ctx,
22
+ const char *name, unsigned name_size, const char *path);
23
+ grn_obj *grn_column_open(grn_ctx *ctx, grn_obj *table,
24
+ const char *name, unsigned name_size,
25
+ const char *path, grn_obj *type);
26
+
27
+ #define SELF(object) ((RbGrnTable *)DATA_PTR(object))
28
+
29
+ VALUE rb_cGrnTable;
30
+
31
+ static ID id_array_reference;
32
+ static ID id_array_set;
33
+
34
+ /*
35
+ * Document-class: Groonga::Table < Groonga::Object
36
+ *
37
+ * Ruby/groongaが提供するテーブルのベースとなるクラス。このクラス
38
+ * からGroonga::Array, Groonga::Hash, Groonga::PatriciaTrie
39
+ * が継承されている。
40
+ */
41
+
42
+ grn_obj *
43
+ rb_grn_table_from_ruby_object (VALUE object, grn_ctx **context)
44
+ {
45
+ if (!RVAL2CBOOL(rb_obj_is_kind_of(object, rb_cGrnTable))) {
46
+ rb_raise(rb_eTypeError, "not a groonga table");
47
+ }
48
+
49
+ return RVAL2GRNOBJECT(object, context);
50
+ }
51
+
52
+ VALUE
53
+ rb_grn_table_to_ruby_object (grn_ctx *context, grn_obj *table,
54
+ rb_grn_boolean owner)
55
+ {
56
+ return GRNOBJECT2RVAL(Qnil, context, table, owner);
57
+ }
58
+
59
+ void
60
+ rb_grn_table_finalizer (grn_ctx *context, grn_obj *object,
61
+ RbGrnTable *rb_grn_table)
62
+ {
63
+ if (context && rb_grn_table->value)
64
+ grn_obj_unlink(context, rb_grn_table->value);
65
+ rb_grn_table->value = NULL;
66
+ rb_grn_table->columns = Qnil;
67
+ }
68
+
69
+ void
70
+ rb_grn_table_bind (RbGrnTable *rb_grn_table,
71
+ grn_ctx *context, grn_obj *table)
72
+ {
73
+ RbGrnObject *rb_grn_object;
74
+
75
+ rb_grn_object = RB_GRN_OBJECT(rb_grn_table);
76
+ rb_grn_table->value = grn_obj_open(context, GRN_BULK, 0,
77
+ rb_grn_object->range_id);
78
+ rb_grn_table->columns = rb_ary_new();
79
+ }
80
+
81
+ void
82
+ rb_grn_table_deconstruct (RbGrnTable *rb_grn_table,
83
+ grn_obj **table,
84
+ grn_ctx **context,
85
+ grn_id *domain_id,
86
+ grn_obj **domain,
87
+ grn_obj **value,
88
+ grn_id *range_id,
89
+ grn_obj **range,
90
+ VALUE *columns)
91
+ {
92
+ RbGrnObject *rb_grn_object;
93
+
94
+ rb_grn_object = RB_GRN_OBJECT(rb_grn_table);
95
+ rb_grn_object_deconstruct(rb_grn_object, table, context,
96
+ domain_id, domain,
97
+ range_id, range);
98
+
99
+ if (value)
100
+ *value = rb_grn_table->value;
101
+ if (columns)
102
+ *columns = rb_grn_table->columns;
103
+ }
104
+
105
+ static void
106
+ rb_grn_table_mark (void *data)
107
+ {
108
+ RbGrnObject *rb_grn_object = data;
109
+ RbGrnTable *rb_grn_table = data;
110
+ grn_ctx *context;
111
+ grn_obj *table;
112
+
113
+ if (!rb_grn_object)
114
+ return;
115
+
116
+ rb_gc_mark(rb_grn_table->columns);
117
+
118
+ context = rb_grn_object->context;
119
+ table = rb_grn_object->object;
120
+ if (!context || !table)
121
+ return;
122
+
123
+ if (!grn_obj_path(context, table))
124
+ return;
125
+
126
+ if (grn_obj_name(context, table, NULL, 0) == 0)
127
+ return;
128
+ }
129
+
130
+ static VALUE
131
+ rb_grn_table_alloc (VALUE klass)
132
+ {
133
+ return Data_Wrap_Struct(klass, rb_grn_table_mark, rb_grn_object_free, NULL);
134
+ }
135
+
136
+ static VALUE
137
+ rb_grn_table_initialize (VALUE self)
138
+ {
139
+ rb_raise(rb_eArgError, "Use Groonga::Context#[] for get existing table.");
140
+ return Qnil;
141
+ }
142
+
143
+ static VALUE
144
+ rb_grn_table_inspect_content (VALUE self, VALUE inspected)
145
+ {
146
+ RbGrnTable *rb_grn_table;
147
+ grn_ctx *context = NULL;
148
+ grn_obj *table;
149
+ VALUE columns;
150
+
151
+ rb_grn_table = SELF(self);
152
+ if (!rb_grn_table)
153
+ return inspected;
154
+
155
+ rb_grn_table_deconstruct(rb_grn_table, &table, &context,
156
+ NULL, NULL,
157
+ NULL, NULL, NULL,
158
+ &columns);
159
+
160
+ if (!table)
161
+ return inspected;
162
+ if (!context)
163
+ return inspected;
164
+
165
+ if (table->header.type != GRN_TABLE_NO_KEY) {
166
+ grn_obj value;
167
+ grn_encoding encoding;
168
+
169
+ rb_str_cat2(inspected, ", ");
170
+ rb_str_cat2(inspected, "encoding: <");
171
+ GRN_OBJ_INIT(&value, GRN_BULK, 0, GRN_ID_NIL);
172
+ grn_obj_get_info(context, table, GRN_INFO_ENCODING, &value);
173
+ encoding = *((grn_encoding *)GRN_BULK_HEAD(&value));
174
+ grn_obj_unlink(context, &value);
175
+
176
+ if (context->rc == GRN_SUCCESS)
177
+ rb_str_concat(inspected, rb_inspect(GRNENCODING2RVAL(encoding)));
178
+ else
179
+ rb_str_cat2(inspected, "invalid");
180
+
181
+ rb_str_cat2(inspected, ">");
182
+ }
183
+
184
+ rb_str_cat2(inspected, ", ");
185
+ rb_str_cat2(inspected, "size: <");
186
+ {
187
+ char buf[21]; /* ceil(log10(2 ** 64)) + 1('\0') == 21 */
188
+ snprintf(buf, sizeof(buf), "%u", grn_table_size(context, table));
189
+ rb_str_cat2(inspected, buf);
190
+ }
191
+ rb_str_cat2(inspected, ">");
192
+
193
+ /*
194
+ rb_str_cat2(inspected, ", ");
195
+ rb_str_cat2(inspected, "columns: <");
196
+ rb_str_concat(inspected, rb_inspect(columns));
197
+ rb_str_cat2(inspected, ">");
198
+ */
199
+
200
+ return inspected;
201
+ }
202
+
203
+ /*
204
+ * call-seq:
205
+ * _table_.inspect -> String
206
+ *
207
+ * テーブルの中身を人に見やすい文字列で返す。
208
+ */
209
+ static VALUE
210
+ rb_grn_table_inspect (VALUE self)
211
+ {
212
+ VALUE inspected;
213
+
214
+ inspected = rb_str_new2("");
215
+ rb_grn_object_inspect_header(self, inspected);
216
+ rb_grn_object_inspect_content(self, inspected);
217
+ rb_grn_table_inspect_content(self, inspected);
218
+ rb_grn_object_inspect_footer(self, inspected);
219
+
220
+ return inspected;
221
+ }
222
+
223
+ /*
224
+ * call-seq:
225
+ * table.define_column(name, value_type, options={}) ->
226
+ * Groonga::FixSizeColumnかGroonga::VariableSizeColumn
227
+ *
228
+ * テーブルに名前が_name_で型が_value_type_のカラムを定義
229
+ * し、新しく定義されたカラムを返す。
230
+ *
231
+ * _options_に指定可能な値は以下の通り。
232
+ *
233
+ * [+:path+]
234
+ * カラムを保存するパス。
235
+ *
236
+ * [+:persistent+]
237
+ * +true+を指定すると永続カラムとなる。省略した場合は永
238
+ * 続カラムとなる。+:path+を省略した場合は自動的にパスが
239
+ * 付加される。
240
+ *
241
+ * [+:type+]
242
+ * カラムの値の格納方法について指定する。省略した場合は、
243
+ * +:scalar+になる。
244
+ *
245
+ * [+:scalar+]
246
+ * スカラ値(単独の値)を格納する。
247
+ *
248
+ * [+:vector+]
249
+ * 値の配列を格納する。
250
+ *
251
+ * [+:compress+]
252
+ * 値の圧縮方法を指定する。省略した場合は、圧縮しない。
253
+ *
254
+ * [+:zlib+]
255
+ * 値をzlib圧縮して格納する。
256
+ *
257
+ * [+:lzo+]
258
+ * 値をlzo圧縮して格納する。
259
+ */
260
+ static VALUE
261
+ rb_grn_table_define_column (int argc, VALUE *argv, VALUE self)
262
+ {
263
+ grn_ctx *context = NULL;
264
+ grn_obj *table;
265
+ grn_obj *value_type, *column;
266
+ char *name = NULL, *path = NULL;
267
+ unsigned name_size = 0;
268
+ grn_obj_flags flags = 0;
269
+ VALUE rb_name, rb_value_type;
270
+ VALUE options, rb_path, rb_persistent, rb_compress, rb_type;
271
+ VALUE columns;
272
+ VALUE rb_column;
273
+
274
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
275
+ NULL, NULL,
276
+ NULL, NULL, NULL,
277
+ &columns);
278
+
279
+ rb_scan_args(argc, argv, "21", &rb_name, &rb_value_type, &options);
280
+
281
+ name = StringValuePtr(rb_name);
282
+ name_size = RSTRING_LEN(rb_name);
283
+
284
+ rb_grn_scan_options(options,
285
+ "path", &rb_path,
286
+ "persistent", &rb_persistent,
287
+ "type", &rb_type,
288
+ "compress", &rb_compress,
289
+ NULL);
290
+
291
+ value_type = RVAL2GRNOBJECT(rb_value_type, &context);
292
+
293
+ if ((NIL_P(rb_persistent) && grn_obj_path(context, table)) ||
294
+ RVAL2CBOOL(rb_persistent)) {
295
+ flags |= GRN_OBJ_PERSISTENT;
296
+ }
297
+
298
+ if (!NIL_P(rb_path)) {
299
+ path = StringValueCStr(rb_path);
300
+ if ((flags & GRN_OBJ_PERSISTENT) != GRN_OBJ_PERSISTENT) {
301
+ rb_raise(rb_eArgError,
302
+ "should not pass :path if :persistent is false: <%s>",
303
+ path);
304
+ }
305
+ flags |= GRN_OBJ_PERSISTENT;
306
+ }
307
+
308
+ if (NIL_P(rb_type) ||
309
+ (rb_grn_equal_option(rb_type, "scalar"))) {
310
+ flags |= GRN_OBJ_COLUMN_SCALAR;
311
+ } else if (rb_grn_equal_option(rb_type, "vector")) {
312
+ flags |= GRN_OBJ_COLUMN_VECTOR;
313
+ } else {
314
+ rb_raise(rb_eArgError,
315
+ "invalid column type: %s: "
316
+ "available types: [:scalar, :vector, nil]",
317
+ rb_grn_inspect(rb_type));
318
+ }
319
+
320
+ if (NIL_P(rb_compress)) {
321
+ } else if (rb_grn_equal_option(rb_compress, "zlib")) {
322
+ flags |= GRN_OBJ_COMPRESS_ZLIB;
323
+ } else if (rb_grn_equal_option(rb_compress, "lzo")) {
324
+ flags |= GRN_OBJ_COMPRESS_LZO;
325
+ } else {
326
+ rb_raise(rb_eArgError,
327
+ "invalid compress type: %s: "
328
+ "available types: [:zlib, :lzo, nil]",
329
+ rb_grn_inspect(rb_compress));
330
+ }
331
+
332
+ column = grn_column_create(context, table, name, name_size,
333
+ path, flags, value_type);
334
+ if (context->rc) {
335
+ rb_grn_context_check(context,
336
+ rb_ary_new3(2, self, rb_ary_new4(argc, argv)));
337
+ }
338
+
339
+ rb_column = GRNCOLUMN2RVAL(Qnil, context, column, RB_GRN_TRUE);
340
+ rb_ary_push(columns, rb_column);
341
+ rb_grn_named_object_set_name(RB_GRN_NAMED_OBJECT(DATA_PTR(rb_column)),
342
+ name, name_size);
343
+
344
+ return rb_column;
345
+ }
346
+
347
+ /*
348
+ * call-seq:
349
+ * table.define_index_column(name, value_type, options={}) -> Groonga::IndexColumn
350
+ *
351
+ * テーブルに名前が_name_で型が_value_type_のインデックスカ
352
+ * ラムを定義し、新しく定義されたカラムを返す。
353
+ *
354
+ * _options_に指定可能な値は以下の通り。
355
+ *
356
+ * [+:path+]
357
+ * カラムを保存するパス。
358
+ *
359
+ * [+:persistent+]
360
+ * +true+を指定すると永続カラムとなる。省略した場合は永
361
+ * 続カラムとなる。+:path+を省略した場合は自動的にパスが
362
+ * 付加される。
363
+ *
364
+ * [+:with_section+]
365
+ * 転置索引にsection(段落情報)を合わせて格納する。
366
+ *
367
+ * [+:with_weight+]
368
+ * 転置索引にweight情報を合わせて格納する。
369
+ *
370
+ * [+:with_position+]
371
+ * 転置索引に出現位置情報を合わせて格納する。
372
+ *
373
+ * [+:source+]
374
+ * インデックス対象となるカラムを指定する。+:sources+との併用はできない。
375
+ *
376
+ * [+:sources+]
377
+ * インデックス対象となる複数のカラムを指定する。+:source+との併用はできない。
378
+ */
379
+ static VALUE
380
+ rb_grn_table_define_index_column (int argc, VALUE *argv, VALUE self)
381
+ {
382
+ grn_ctx *context = NULL;
383
+ grn_obj *table;
384
+ grn_obj *value_type, *column;
385
+ char *name = NULL, *path = NULL;
386
+ unsigned name_size = 0;
387
+ grn_obj_flags flags = GRN_OBJ_COLUMN_INDEX;
388
+ VALUE rb_name, rb_value_type;
389
+ VALUE options, rb_path, rb_persistent;
390
+ VALUE rb_with_section, rb_with_weight, rb_with_position;
391
+ VALUE rb_column, rb_source, rb_sources;
392
+ VALUE columns;
393
+
394
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
395
+ NULL, NULL,
396
+ NULL, NULL, NULL,
397
+ &columns);
398
+
399
+ rb_scan_args(argc, argv, "21", &rb_name, &rb_value_type, &options);
400
+
401
+ name = StringValuePtr(rb_name);
402
+ name_size = RSTRING_LEN(rb_name);
403
+
404
+ rb_grn_scan_options(options,
405
+ "path", &rb_path,
406
+ "persistent", &rb_persistent,
407
+ "with_section", &rb_with_section,
408
+ "with_weight", &rb_with_weight,
409
+ "with_position", &rb_with_position,
410
+ "source", &rb_source,
411
+ "sources", &rb_sources,
412
+ NULL);
413
+
414
+ value_type = RVAL2GRNOBJECT(rb_value_type, &context);
415
+
416
+ if ((NIL_P(rb_persistent) && grn_obj_path(context, table)) ||
417
+ RVAL2CBOOL(rb_persistent)) {
418
+ flags |= GRN_OBJ_PERSISTENT;
419
+ }
420
+
421
+ if (!NIL_P(rb_path)) {
422
+ path = StringValueCStr(rb_path);
423
+ if ((flags & GRN_OBJ_PERSISTENT) != GRN_OBJ_PERSISTENT) {
424
+ rb_raise(rb_eArgError,
425
+ "should not pass :path if :persistent is false: <%s>",
426
+ path);
427
+ }
428
+ flags |= GRN_OBJ_PERSISTENT;
429
+ }
430
+
431
+ if (RVAL2CBOOL(rb_with_section))
432
+ flags |= GRN_OBJ_WITH_SECTION;
433
+
434
+ if (RVAL2CBOOL(rb_with_weight))
435
+ flags |= GRN_OBJ_WITH_WEIGHT;
436
+
437
+ if (NIL_P(rb_with_position) &&
438
+ (table->header.type == GRN_TABLE_HASH_KEY ||
439
+ table->header.type == GRN_TABLE_PAT_KEY)) {
440
+ grn_id tokenizer_id;
441
+ grn_obj *tokenizer;
442
+
443
+ tokenizer = grn_obj_get_info(context, table,
444
+ GRN_INFO_DEFAULT_TOKENIZER,
445
+ NULL);
446
+ tokenizer_id = grn_obj_id(context, tokenizer);
447
+ if ((tokenizer_id == GRN_DB_UNIGRAM) ||
448
+ (tokenizer_id == GRN_DB_BIGRAM) ||
449
+ (tokenizer_id == GRN_DB_TRIGRAM)) {
450
+ rb_with_position = Qtrue;
451
+ }
452
+ }
453
+ if (RVAL2CBOOL(rb_with_position))
454
+ flags |= GRN_OBJ_WITH_POSITION;
455
+
456
+ if (!NIL_P(rb_source) && !NIL_P(rb_sources))
457
+ rb_raise(rb_eArgError, "should not pass both of :source and :sources.");
458
+
459
+ column = grn_column_create(context, table, name, name_size,
460
+ path, flags, value_type);
461
+ if (context->rc) {
462
+ rb_grn_context_check(context,
463
+ rb_ary_new3(2, self, rb_ary_new4(argc, argv)));
464
+ }
465
+
466
+ rb_column = GRNCOLUMN2RVAL(Qnil, context, column, RB_GRN_TRUE);
467
+ if (!NIL_P(rb_source))
468
+ rb_funcall(rb_column, rb_intern("source="), 1, rb_source);
469
+ if (!NIL_P(rb_sources))
470
+ rb_funcall(rb_column, rb_intern("sources="), 1, rb_sources);
471
+
472
+ rb_ary_push(columns, rb_column);
473
+ rb_grn_named_object_set_name(RB_GRN_NAMED_OBJECT(DATA_PTR(rb_column)),
474
+ name, name_size);
475
+
476
+ return rb_column;
477
+ }
478
+
479
+ static void
480
+ ruby_object_to_column_name (VALUE rb_name,
481
+ const char **name, unsigned *name_size)
482
+ {
483
+ switch (TYPE(rb_name)) {
484
+ case T_SYMBOL:
485
+ *name = rb_id2name(SYM2ID(rb_name));
486
+ *name_size = strlen(*name);
487
+ break;
488
+ case T_STRING:
489
+ *name = StringValuePtr(rb_name);
490
+ *name_size = RSTRING_LEN(rb_name);
491
+ break;
492
+ default:
493
+ rb_raise(rb_eArgError,
494
+ "column name should be String or Symbol: %s",
495
+ rb_grn_inspect(rb_name));
496
+ break;
497
+ }
498
+ }
499
+
500
+ /*
501
+ * call-seq:
502
+ * table.column(name) -> Groonga::Column or nil
503
+ *
504
+ * テーブルの_name_に対応するカラムを返す。カラムが存在しな
505
+ * い場合は+nil+を返す。
506
+ */
507
+ VALUE
508
+ rb_grn_table_get_column (VALUE self, VALUE rb_name)
509
+ {
510
+ grn_user_data *user_data;
511
+ grn_ctx *context = NULL;
512
+ grn_obj *table;
513
+ grn_obj *column;
514
+ const char *name = NULL;
515
+ unsigned name_size = 0;
516
+ rb_grn_boolean owner;
517
+ VALUE rb_column;
518
+ VALUE columns;
519
+ VALUE *raw_columns;
520
+ long i, n;
521
+
522
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
523
+ NULL, NULL,
524
+ NULL, NULL, NULL,
525
+ &columns);
526
+
527
+ ruby_object_to_column_name(rb_name, &name, &name_size);
528
+ raw_columns = RARRAY_PTR(columns);
529
+ n = RARRAY_LEN(columns);
530
+ for (i = 0; i < n; i++) {
531
+ VALUE rb_column = raw_columns[i];
532
+ RbGrnNamedObject *rb_grn_named_object;
533
+
534
+ rb_grn_named_object = RB_GRN_NAMED_OBJECT(DATA_PTR(rb_column));
535
+ if (name_size == rb_grn_named_object->name_size &&
536
+ memcmp(name, rb_grn_named_object->name, name_size) == 0) {
537
+ return rb_column;
538
+ }
539
+ }
540
+
541
+ column = grn_obj_column(context, table, name, name_size);
542
+ rb_grn_context_check(context, self);
543
+ if (!column)
544
+ return Qnil;
545
+
546
+ user_data = grn_obj_user_data(context, column);
547
+ if (user_data) {
548
+ RbGrnObject *rb_grn_object;
549
+ rb_grn_object = user_data->ptr;
550
+ if (rb_grn_object) {
551
+ rb_ary_push(columns, rb_grn_object->self);
552
+ return rb_grn_object->self;
553
+ }
554
+ }
555
+
556
+ owner = column->header.type == GRN_ACCESSOR;
557
+ rb_column = GRNCOLUMN2RVAL(Qnil, context, column, owner);
558
+ if (owner) {
559
+ rb_iv_set(rb_column, "table", self);
560
+ }
561
+ rb_grn_named_object_set_name(RB_GRN_NAMED_OBJECT(DATA_PTR(rb_column)),
562
+ name, name_size);
563
+
564
+ return rb_column;
565
+ }
566
+
567
+ VALUE
568
+ rb_grn_table_get_column_surely (VALUE self, VALUE rb_name)
569
+ {
570
+ VALUE rb_column;
571
+
572
+ rb_column = rb_grn_table_get_column(self, rb_name);
573
+ if (NIL_P(rb_column)) {
574
+ rb_raise(rb_eGrnNoSuchColumn,
575
+ "no such column: <%s>: <%s>",
576
+ rb_grn_inspect(rb_name), rb_grn_inspect(self));
577
+ }
578
+ return rb_column;
579
+ }
580
+
581
+ /*
582
+ * call-seq:
583
+ * table.columns(name=nil) -> Groonga::Columnの配列
584
+ *
585
+ * テーブルの全てのカラムを返す。_name_が指定された場合はカ
586
+ * ラム名の先頭が_name_で始まるカラムを返す。
587
+ */
588
+ static VALUE
589
+ rb_grn_table_get_columns (int argc, VALUE *argv, VALUE self)
590
+ {
591
+ grn_ctx *context = NULL;
592
+ grn_obj *table;
593
+ grn_obj *columns;
594
+ grn_rc rc;
595
+ int n;
596
+ grn_table_cursor *cursor;
597
+ VALUE rb_name, rb_columns;
598
+ char *name = NULL;
599
+ unsigned name_size = 0;
600
+
601
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
602
+ NULL, NULL,
603
+ NULL, NULL, NULL,
604
+ NULL);
605
+
606
+ rb_scan_args(argc, argv, "01", &rb_name);
607
+
608
+ if (!NIL_P(rb_name)) {
609
+ name = StringValuePtr(rb_name);
610
+ name_size = RSTRING_LEN(rb_name);
611
+ }
612
+
613
+ columns = grn_table_create(context, NULL, 0, NULL, GRN_TABLE_HASH_KEY,
614
+ NULL, 0);
615
+ n = grn_table_columns(context, table, name, name_size, columns);
616
+ rb_grn_context_check(context, self);
617
+
618
+ rb_columns = rb_ary_new2(n);
619
+ if (n == 0)
620
+ return rb_columns;
621
+
622
+ cursor = grn_table_cursor_open(context, columns, NULL, 0, NULL, 0,
623
+ 0, -1, GRN_CURSOR_ASCENDING);
624
+ rb_grn_context_check(context, self);
625
+ while (grn_table_cursor_next(context, cursor) != GRN_ID_NIL) {
626
+ void *key;
627
+ grn_id *column_id;
628
+ grn_obj *column;
629
+ VALUE rb_column;
630
+
631
+ grn_table_cursor_get_key(context, cursor, &key);
632
+ column_id = key;
633
+ column = grn_ctx_at(context, *column_id);
634
+ rb_column = GRNOBJECT2RVAL(Qnil, context, column, RB_GRN_FALSE);
635
+ rb_ary_push(rb_columns, rb_column);
636
+ }
637
+ rc = grn_table_cursor_close(context, cursor);
638
+ if (rc != GRN_SUCCESS) {
639
+ rb_grn_context_check(context, self);
640
+ rb_grn_rc_check(rc, self);
641
+ }
642
+
643
+ return rb_columns;
644
+ }
645
+
646
+ /*
647
+ * call-seq:
648
+ * table.have_column?(name) -> true/false
649
+ *
650
+ * テーブルが_name_カラムを持っている場合は+true+を返す。
651
+ */
652
+ static VALUE
653
+ rb_grn_table_have_column (VALUE self, VALUE rb_name)
654
+ {
655
+ grn_ctx *context = NULL;
656
+ grn_obj *table;
657
+ grn_obj *column;
658
+ const char *name = NULL;
659
+ unsigned name_size = 0;
660
+ VALUE result = Qfalse;
661
+
662
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
663
+ NULL, NULL,
664
+ NULL, NULL, NULL,
665
+ NULL);
666
+
667
+ ruby_object_to_column_name(rb_name, &name, &name_size);
668
+ column = grn_obj_column(context, table, name, name_size);
669
+ if (!column)
670
+ return Qfalse;
671
+
672
+ if (column->header.type != GRN_ACCESSOR)
673
+ result = Qtrue;
674
+ grn_obj_unlink(context, column);
675
+
676
+ return result;
677
+ }
678
+
679
+ static grn_table_cursor *
680
+ rb_grn_table_open_grn_cursor (int argc, VALUE *argv, VALUE self,
681
+ grn_ctx **context)
682
+ {
683
+ grn_obj *table;
684
+ grn_table_cursor *cursor;
685
+ void *min_key = NULL, *max_key = NULL;
686
+ unsigned min_key_size = 0, max_key_size = 0;
687
+ int offset = 0, limit = -1;
688
+ int flags = 0;
689
+ VALUE options, rb_min, rb_max, rb_order, rb_greater_than, rb_less_than;
690
+ VALUE rb_offset, rb_limit;
691
+
692
+ rb_grn_table_deconstruct(SELF(self), &table, context,
693
+ NULL, NULL,
694
+ NULL, NULL, NULL,
695
+ NULL);
696
+
697
+ rb_scan_args(argc, argv, "01", &options);
698
+
699
+ rb_grn_scan_options(options,
700
+ "min", &rb_min,
701
+ "max", &rb_max,
702
+ "offset", &rb_offset,
703
+ "limit", &rb_limit,
704
+ "order", &rb_order,
705
+ "greater_than", &rb_greater_than,
706
+ "less_than", &rb_less_than,
707
+ NULL);
708
+
709
+ if (!NIL_P(rb_min)) {
710
+ min_key = StringValuePtr(rb_min);
711
+ min_key_size = RSTRING_LEN(rb_min);
712
+ }
713
+ if (!NIL_P(rb_max)) {
714
+ max_key = StringValuePtr(rb_max);
715
+ max_key_size = RSTRING_LEN(rb_max);
716
+ }
717
+ if (!NIL_P(rb_offset))
718
+ offset = NUM2INT(rb_offset);
719
+ if (!NIL_P(rb_limit))
720
+ limit = NUM2INT(rb_limit);
721
+
722
+ if (NIL_P(rb_order)) {
723
+ } else if (rb_grn_equal_option(rb_order, "asc") ||
724
+ rb_grn_equal_option(rb_order, "ascending")) {
725
+ flags |= GRN_CURSOR_ASCENDING;
726
+ } else if (rb_grn_equal_option(rb_order, "desc") ||
727
+ rb_grn_equal_option(rb_order, "descending")) {
728
+ flags |= GRN_CURSOR_DESCENDING;
729
+ } else {
730
+ rb_raise(rb_eArgError,
731
+ "order should be one of "
732
+ "[:asc, :ascending, :desc, :descending]: %s",
733
+ rb_grn_inspect(rb_order));
734
+ }
735
+
736
+ if (RVAL2CBOOL(rb_greater_than))
737
+ flags |= GRN_CURSOR_GT;
738
+ if (RVAL2CBOOL(rb_less_than))
739
+ flags |= GRN_CURSOR_LT;
740
+
741
+ cursor = grn_table_cursor_open(*context, table,
742
+ min_key, min_key_size,
743
+ max_key, max_key_size,
744
+ offset, limit, flags);
745
+ rb_grn_context_check(*context, self);
746
+
747
+ return cursor;
748
+ }
749
+
750
+ /*
751
+ * call-seq:
752
+ * table.open_cursor(options={}) -> Groonga::TableCursor
753
+ * table.open_cursor(options={}) {|cursor| ... }
754
+ *
755
+ * カーソルを生成して返す。ブロックを指定すると、そのブロッ
756
+ * クに生成したカーソルが渡され、ブロックを抜けると自動的に
757
+ * カーソルが破棄される。
758
+ *
759
+ * _options_に指定可能な値は以下の通り。
760
+ *
761
+ * [+:min+]
762
+ * キーの下限
763
+ *
764
+ * [+:max+]
765
+ * キーの上限
766
+ *
767
+ * [+:offset+]
768
+ * 該当する範囲のレコードのうち、(0ベースで)_:offset_番目
769
+ * からレコードを取り出す。
770
+ *
771
+ * [+:limit+]
772
+ * 該当する範囲のレコードのうち、_:limit_件のみを取り出す。
773
+ * 省略された場合または-1が指定された場合は、全件が指定され
774
+ * たものとみなす。
775
+ *
776
+ * [+:order+]
777
+ * +:asc+または+:ascending+を指定すると昇順にレコードを取
778
+ * り出す。
779
+ * +:desc+または+:descending+を指定すると降順にレコードを
780
+ * 取り出す。
781
+ *
782
+ * [+:greater_than+]
783
+ * +true+を指定すると+:min+で指定した値に一致した[+key+]を
784
+ * 範囲に含まない。
785
+ *
786
+ * [+:less_than+]
787
+ * +true+を指定すると+:max+で指定した値に一致した[+key+]を
788
+ * 範囲に含まない。
789
+ */
790
+ static VALUE
791
+ rb_grn_table_open_cursor (int argc, VALUE *argv, VALUE self)
792
+ {
793
+ grn_ctx *context = NULL;
794
+ grn_table_cursor *cursor;
795
+ VALUE rb_cursor;
796
+
797
+ cursor = rb_grn_table_open_grn_cursor(argc, argv, self, &context);
798
+ rb_cursor = GRNTABLECURSOR2RVAL(Qnil, context, cursor);
799
+ rb_iv_set(rb_cursor, "@table", self); /* FIXME: cursor should mark table */
800
+ if (rb_block_given_p())
801
+ return rb_ensure(rb_yield, rb_cursor, rb_grn_object_close, rb_cursor);
802
+ else
803
+ return rb_cursor;
804
+ }
805
+
806
+ /*
807
+ * call-seq:
808
+ * table.records -> Groonga::Recordの配列
809
+ *
810
+ * テーブルに登録されている全てのレコードが入っている配列を
811
+ * 返す。
812
+ */
813
+ static VALUE
814
+ rb_grn_table_get_records (int argc, VALUE *argv, VALUE self)
815
+ {
816
+ grn_ctx *context = NULL;
817
+ grn_table_cursor *cursor;
818
+ grn_id record_id;
819
+ VALUE records;
820
+
821
+ cursor = rb_grn_table_open_grn_cursor(argc, argv, self, &context);
822
+ records = rb_ary_new();
823
+ while ((record_id = grn_table_cursor_next(context, cursor))) {
824
+ rb_ary_push(records, rb_grn_record_new(self, record_id, Qnil));
825
+ }
826
+ grn_table_cursor_close(context, cursor);
827
+
828
+ return records;
829
+ }
830
+
831
+ /*
832
+ * call-seq:
833
+ * table.size -> レコード数
834
+ *
835
+ * テーブルに登録されているレコード数を返す。
836
+ */
837
+ static VALUE
838
+ rb_grn_table_get_size (VALUE self)
839
+ {
840
+ grn_ctx *context = NULL;
841
+ grn_obj *table;
842
+ unsigned int size;
843
+
844
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
845
+ NULL, NULL,
846
+ NULL, NULL, NULL,
847
+ NULL);
848
+ size = grn_table_size(context, table);
849
+ return UINT2NUM(size);
850
+ }
851
+
852
+ /*
853
+ * call-seq:
854
+ * table.empty? -> true/false
855
+ *
856
+ * テーブルにレコードが登録されていなければ+true+を返す。
857
+ */
858
+ static VALUE
859
+ rb_grn_table_empty_p (VALUE self)
860
+ {
861
+ grn_ctx *context = NULL;
862
+ grn_obj *table;
863
+ unsigned int size;
864
+
865
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
866
+ NULL, NULL,
867
+ NULL, NULL, NULL,
868
+ NULL);
869
+ size = grn_table_size(context, table);
870
+ return size == 0;
871
+ }
872
+
873
+ /*
874
+ * call-seq:
875
+ * table.truncate
876
+ *
877
+ * テーブルの全レコードを一括して削除する。
878
+ */
879
+ static VALUE
880
+ rb_grn_table_truncate (VALUE self)
881
+ {
882
+ grn_ctx *context = NULL;
883
+ grn_obj *table;
884
+ grn_rc rc;
885
+
886
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
887
+ NULL, NULL,
888
+ NULL, NULL, NULL,
889
+ NULL);
890
+ rc = grn_table_truncate(context, table);
891
+ rb_grn_rc_check(rc, self);
892
+
893
+ return Qnil;
894
+ }
895
+
896
+ /*
897
+ * call-seq:
898
+ * table.each {|record| ...}
899
+ *
900
+ * テーブルに登録されているレコードを順番にブロックに渡す。
901
+ */
902
+ static VALUE
903
+ rb_grn_table_each (VALUE self)
904
+ {
905
+ RbGrnTable *rb_table;
906
+ RbGrnObject *rb_grn_object;
907
+ grn_ctx *context = NULL;
908
+ grn_obj *table;
909
+ grn_table_cursor *cursor;
910
+ VALUE rb_cursor;
911
+ grn_id id;
912
+
913
+ rb_table = SELF(self);
914
+ rb_grn_table_deconstruct(rb_table, &table, &context,
915
+ NULL, NULL,
916
+ NULL, NULL, NULL,
917
+ NULL);
918
+ cursor = grn_table_cursor_open(context, table, NULL, 0, NULL, 0,
919
+ 0, -1, GRN_CURSOR_ASCENDING);
920
+ rb_cursor = GRNTABLECURSOR2RVAL(Qnil, context, cursor);
921
+ rb_grn_object = RB_GRN_OBJECT(rb_table);
922
+ while (rb_grn_object->object &&
923
+ (id = grn_table_cursor_next(context, cursor)) != GRN_ID_NIL) {
924
+ rb_yield(rb_grn_record_new(self, id, Qnil));
925
+ }
926
+ rb_grn_object_close(rb_cursor);
927
+
928
+ return Qnil;
929
+ }
930
+
931
+ /*
932
+ * call-seq:
933
+ * table.delete(id)
934
+ *
935
+ * テーブルの_id_に対応するレコードを削除する。
936
+ */
937
+ VALUE
938
+ rb_grn_table_delete (VALUE self, VALUE rb_id)
939
+ {
940
+ grn_ctx *context = NULL;
941
+ grn_obj *table;
942
+ grn_id id;
943
+ grn_rc rc;
944
+
945
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
946
+ NULL, NULL,
947
+ NULL, NULL, NULL,
948
+ NULL);
949
+
950
+ id = NUM2UINT(rb_id);
951
+ rc = grn_table_delete_by_id(context, table, id);
952
+ rb_grn_rc_check(rc, self);
953
+
954
+ return Qnil;
955
+ }
956
+
957
+ /*
958
+ * call-seq:
959
+ * table.sort(keys, options={}) -> Groonga::Recordの配列
960
+ *
961
+ * テーブルに登録されているレコードを_keys_で指定されたルー
962
+ * ルに従ってソートしたレコードの配列を返す。
963
+ *
964
+ * [
965
+ * {:key => "カラム名", :order => :asc, :ascending,
966
+ * :desc, :descendingのいずれか},
967
+ * {:key => "カラム名", :order => :asc, :ascending,
968
+ * :desc, :descendingのいずれか},
969
+ * ...,
970
+ * ]
971
+ *
972
+ * _options_に指定可能な値は以下の通り。
973
+ *
974
+ * [+:offset+]
975
+ * ソートされたレコードのうち、(0ベースで)_:offset_番目
976
+ * からレコードを取り出す。
977
+ *
978
+ * [+:limit+]
979
+ * ソートされたレコードのうち、_:limit_件のみを取り出す。
980
+ * 省略された場合または-1が指定された場合は、全件が指定され
981
+ * たものとみなす。
982
+ */
983
+ static VALUE
984
+ rb_grn_table_sort (int argc, VALUE *argv, VALUE self)
985
+ {
986
+ grn_ctx *context = NULL;
987
+ grn_obj *table;
988
+ grn_obj *result;
989
+ grn_table_sort_key *keys;
990
+ int i, n_keys;
991
+ int n_records, offset = 0, limit = -1;
992
+ VALUE rb_keys, options;
993
+ VALUE rb_offset, rb_limit;
994
+ VALUE *rb_sort_keys;
995
+ grn_table_cursor *cursor;
996
+ VALUE rb_result;
997
+ VALUE exception;
998
+
999
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1000
+ NULL, NULL,
1001
+ NULL, NULL, NULL,
1002
+ NULL);
1003
+
1004
+ rb_scan_args(argc, argv, "11", &rb_keys, &options);
1005
+
1006
+ if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_keys, rb_cArray)))
1007
+ rb_raise(rb_eArgError, "keys should be an array of key: <%s>",
1008
+ rb_grn_inspect(rb_keys));
1009
+
1010
+ n_keys = RARRAY_LEN(rb_keys);
1011
+ rb_sort_keys = RARRAY_PTR(rb_keys);
1012
+ keys = ALLOCA_N(grn_table_sort_key, n_keys);
1013
+ for (i = 0; i < n_keys; i++) {
1014
+ VALUE rb_sort_options, rb_key, rb_resolved_key, rb_order;
1015
+
1016
+ if (RVAL2CBOOL(rb_obj_is_kind_of(rb_sort_keys[i], rb_cHash))) {
1017
+ rb_sort_options = rb_sort_keys[i];
1018
+ } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_sort_keys[i], rb_cArray))) {
1019
+ rb_sort_options = rb_hash_new();
1020
+ rb_hash_aset(rb_sort_options,
1021
+ RB_GRN_INTERN("key"),
1022
+ rb_ary_entry(rb_sort_keys[i], 0));
1023
+ rb_hash_aset(rb_sort_options,
1024
+ RB_GRN_INTERN("order"),
1025
+ rb_ary_entry(rb_sort_keys[i], 1));
1026
+ } else {
1027
+ rb_sort_options = rb_hash_new();
1028
+ rb_hash_aset(rb_sort_options,
1029
+ RB_GRN_INTERN("key"),
1030
+ rb_sort_keys[i]);
1031
+ }
1032
+ rb_grn_scan_options(rb_sort_options,
1033
+ "key", &rb_key,
1034
+ "order", &rb_order,
1035
+ NULL);
1036
+ if (RVAL2CBOOL(rb_obj_is_kind_of(rb_key, rb_cString))) {
1037
+ rb_resolved_key = rb_grn_table_get_column(self, rb_key);
1038
+ } else {
1039
+ rb_resolved_key = rb_key;
1040
+ }
1041
+ keys[i].key = RVAL2GRNOBJECT(rb_resolved_key, &context);
1042
+ if (!keys[i].key) {
1043
+ rb_raise(rb_eGrnNoSuchColumn,
1044
+ "no such column: <%s>: <%s>",
1045
+ rb_grn_inspect(rb_key), rb_grn_inspect(self));
1046
+ }
1047
+ if (NIL_P(rb_order)) {
1048
+ keys[i].flags = 0;
1049
+ } else if (rb_grn_equal_option(rb_order, "desc") ||
1050
+ rb_grn_equal_option(rb_order, "descending")) {
1051
+ keys[i].flags = GRN_TABLE_SORT_DESC;
1052
+ } else if (rb_grn_equal_option(rb_order, "asc") ||
1053
+ rb_grn_equal_option(rb_order, "ascending")) {
1054
+ keys[i].flags = GRN_TABLE_SORT_ASC;
1055
+ } else {
1056
+ rb_raise(rb_eArgError,
1057
+ "order should be one of "
1058
+ "[nil, :desc, :descending, :asc, :ascending]: %s",
1059
+ rb_grn_inspect(rb_order));
1060
+ }
1061
+ }
1062
+
1063
+ rb_grn_scan_options(options,
1064
+ "offset", &rb_offset,
1065
+ "limit", &rb_limit,
1066
+ NULL);
1067
+
1068
+ if (!NIL_P(rb_offset))
1069
+ offset = NUM2INT(rb_offset);
1070
+ if (!NIL_P(rb_limit))
1071
+ limit = NUM2INT(rb_limit);
1072
+
1073
+ result = grn_table_create(context, NULL, 0, NULL, GRN_TABLE_NO_KEY,
1074
+ NULL, table);
1075
+ n_records = grn_table_sort(context, table, offset, limit,
1076
+ result, keys, n_keys);
1077
+ exception = rb_grn_context_to_exception(context, self);
1078
+ if (!NIL_P(exception)) {
1079
+ grn_obj_unlink(context, result);
1080
+ rb_exc_raise(exception);
1081
+ }
1082
+
1083
+ rb_result = rb_ary_new();
1084
+ cursor = grn_table_cursor_open(context, result, NULL, 0, NULL, 0,
1085
+ 0, -1, GRN_CURSOR_ASCENDING);
1086
+ while (grn_table_cursor_next(context, cursor) != GRN_ID_NIL) {
1087
+ void *value;
1088
+ grn_id *id;
1089
+
1090
+ grn_table_cursor_get_value(context, cursor, &value);
1091
+ id = value;
1092
+ rb_ary_push(rb_result, rb_grn_record_new(self, *id, Qnil));
1093
+ }
1094
+ grn_table_cursor_close(context, cursor);
1095
+ grn_obj_unlink(context, result);
1096
+
1097
+ return rb_result;
1098
+ }
1099
+
1100
+ /*
1101
+ * call-seq:
1102
+ * table.group(key, options={}) -> Groonga::Hash
1103
+ * table.group([key1, key1, ...], options={}) -> [Groonga::Hash, ...]
1104
+ *
1105
+ * _table_のレコードを_key1_, _key2_, _..._で指定したキーの
1106
+ * 値でグループ化する。多くの場合、キーにはカラムを指定する。
1107
+ * カラムはカラム名(文字列)でも指定可能。
1108
+ */
1109
+ static VALUE
1110
+ rb_grn_table_group (int argc, VALUE *argv, VALUE self)
1111
+ {
1112
+ grn_ctx *context = NULL;
1113
+ grn_obj *table;
1114
+ grn_table_sort_key *keys;
1115
+ grn_table_group_result *results;
1116
+ int i, n_keys, n_results;
1117
+ grn_rc rc;
1118
+ VALUE rb_keys, rb_options;
1119
+ VALUE *rb_group_keys;
1120
+ VALUE rb_results;
1121
+
1122
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1123
+ NULL, NULL,
1124
+ NULL, NULL, NULL,
1125
+ NULL);
1126
+
1127
+ rb_scan_args(argc, argv, "11", &rb_keys, &rb_options);
1128
+
1129
+ if (TYPE(rb_keys) == rb_cArray) {
1130
+ n_keys = RARRAY_LEN(rb_keys);
1131
+ rb_group_keys = RARRAY_PTR(rb_keys);
1132
+ } else {
1133
+ n_keys = 1;
1134
+ rb_group_keys = &rb_keys;
1135
+ }
1136
+
1137
+ keys = ALLOCA_N(grn_table_sort_key, n_keys);
1138
+ for (i = 0; i < n_keys; i++) {
1139
+ VALUE rb_sort_options, rb_key;
1140
+
1141
+ if (RVAL2CBOOL(rb_obj_is_kind_of(rb_group_keys[i], rb_cHash))) {
1142
+ rb_sort_options = rb_group_keys[i];
1143
+ } else {
1144
+ rb_sort_options = rb_hash_new();
1145
+ rb_hash_aset(rb_sort_options,
1146
+ RB_GRN_INTERN("key"),
1147
+ rb_group_keys[i]);
1148
+ }
1149
+ rb_grn_scan_options(rb_sort_options,
1150
+ "key", &rb_key,
1151
+ NULL);
1152
+ if (RVAL2CBOOL(rb_obj_is_kind_of(rb_key, rb_cString)))
1153
+ rb_key = rb_grn_table_get_column(self, rb_key);
1154
+ keys[i].key = RVAL2GRNOBJECT(rb_key, &context);
1155
+ keys[i].flags = 0;
1156
+ }
1157
+
1158
+ n_results = n_keys;
1159
+ results = ALLOCA_N(grn_table_group_result, n_results);
1160
+ rb_results = rb_ary_new();
1161
+ for (i = 0; i < n_results; i++) {
1162
+ grn_obj *result;
1163
+ grn_id range_id;
1164
+ VALUE rb_result;
1165
+
1166
+ range_id = grn_obj_get_range(context, keys[i].key);
1167
+ result = grn_table_create(context, NULL, 0, NULL,
1168
+ GRN_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
1169
+ grn_ctx_at(context, range_id), 0);
1170
+ results[i].table = result;
1171
+ results[i].key_begin = 0;
1172
+ results[i].key_end = 0;
1173
+ results[i].limit = 0;
1174
+ results[i].flags = 0;
1175
+ results[i].op = GRN_OP_OR;
1176
+
1177
+ rb_result = GRNOBJECT2RVAL(Qnil, context, result, RB_GRN_TRUE);
1178
+ rb_ary_push(rb_results, rb_result);
1179
+ }
1180
+
1181
+ rc = grn_table_group(context, table, keys, n_keys, results, n_results);
1182
+ rb_grn_context_check(context, self);
1183
+ rb_grn_rc_check(rc, self);
1184
+
1185
+ if (n_results == 1)
1186
+ return rb_ary_pop(rb_results);
1187
+ else
1188
+ return rb_results;
1189
+ }
1190
+
1191
+ /*
1192
+ * Document-method: []
1193
+ *
1194
+ * call-seq:
1195
+ * table[id] -> Groonga::Record
1196
+ *
1197
+ * _table_の_id_に対応するGroonga::Recordを返す。
1198
+ *
1199
+ * 0.9.0から値ではなくGroonga::Recordを返すようになった。
1200
+ */
1201
+ VALUE
1202
+ rb_grn_table_array_reference (VALUE self, VALUE rb_id)
1203
+ {
1204
+ return rb_grn_record_new_raw(self, rb_id, Qnil);
1205
+ }
1206
+
1207
+ VALUE
1208
+ rb_grn_table_get_value (VALUE self, VALUE rb_id)
1209
+ {
1210
+ grn_id id;
1211
+ grn_ctx *context;
1212
+ grn_obj *table;
1213
+ grn_obj *range;
1214
+ grn_obj *value;
1215
+
1216
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1217
+ NULL, NULL,
1218
+ &value, NULL, &range,
1219
+ NULL);
1220
+
1221
+ id = NUM2UINT(rb_id);
1222
+ GRN_BULK_REWIND(value);
1223
+ grn_obj_get_value(context, table, id, value);
1224
+ rb_grn_context_check(context, self);
1225
+
1226
+ return GRNBULK2RVAL(context, value, range, self);
1227
+ }
1228
+
1229
+ /*
1230
+ * Document-method: value
1231
+ *
1232
+ * call-seq:
1233
+ * table.value(id) -> 値
1234
+ * table.value(id, :id => true) -> 値
1235
+ *
1236
+ * _table_の_id_に対応する値を返す。
1237
+ *
1238
+ * <tt>:id => true</tt>が指定できるのは利便性のため。
1239
+ * Groonga::ArrayでもGroonga::HashやGroonga::PatriciaTrieと
1240
+ * 同じ引数で動くようになる。
1241
+ */
1242
+ static VALUE
1243
+ rb_grn_table_get_value_convenience (int argc, VALUE *argv, VALUE self)
1244
+ {
1245
+ VALUE rb_id, rb_options;
1246
+
1247
+ rb_scan_args(argc, argv, "11", &rb_id, &rb_options);
1248
+ if (!NIL_P(rb_options)) {
1249
+ VALUE rb_option_id;
1250
+ rb_grn_scan_options(rb_options,
1251
+ "id", &rb_option_id,
1252
+ NULL);
1253
+ if (!(NIL_P(rb_option_id) || RVAL2CBOOL(rb_option_id))) {
1254
+ rb_raise(rb_eArgError, ":id options must be true or nil: %s: %s",
1255
+ rb_grn_inspect(rb_option_id),
1256
+ rb_grn_inspect(rb_ary_new3(2,
1257
+ self, rb_ary_new4(argc, argv))));
1258
+ }
1259
+ }
1260
+
1261
+ return rb_grn_table_get_value(self, rb_id);
1262
+ }
1263
+
1264
+ VALUE
1265
+ rb_grn_table_set_value (VALUE self, VALUE rb_id, VALUE rb_value)
1266
+ {
1267
+ grn_id id;
1268
+ grn_ctx *context;
1269
+ grn_obj *table;
1270
+ grn_obj *range;
1271
+ grn_obj *value;
1272
+ grn_rc rc;
1273
+
1274
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1275
+ NULL, NULL,
1276
+ &value, NULL, &range,
1277
+ NULL);
1278
+
1279
+ id = NUM2UINT(rb_id);
1280
+ GRN_BULK_REWIND(value);
1281
+ RVAL2GRNBULK(rb_value, context, value);
1282
+ rc = grn_obj_set_value(context, table, id, value, GRN_OBJ_SET);
1283
+ rb_grn_context_check(context, self);
1284
+ rb_grn_rc_check(rc, self);
1285
+
1286
+ return Qnil;
1287
+ }
1288
+
1289
+ /*
1290
+ * Document-method: set_value
1291
+ *
1292
+ * call-seq:
1293
+ * table.set_value(id, value)
1294
+ * table.set_value(id, value, :id => true)
1295
+ *
1296
+ * _table_の_id_に対応する値として_value_設定する。既存の値は
1297
+ * 上書きされる。
1298
+ *
1299
+ * <tt>:id => true</tt>が指定できるのは利便性のため。
1300
+ * Groonga::ArrayでもGroonga::HashやGroonga::PatriciaTrieと
1301
+ * 同じ引数で動くようになる。
1302
+ */
1303
+ static VALUE
1304
+ rb_grn_table_set_value_convenience (int argc, VALUE *argv, VALUE self)
1305
+ {
1306
+ VALUE rb_id, rb_value, rb_options;
1307
+
1308
+ rb_scan_args(argc, argv, "21", &rb_id, &rb_value, &rb_options);
1309
+ if (!NIL_P(rb_options)) {
1310
+ VALUE rb_option_id;
1311
+ rb_grn_scan_options(rb_options,
1312
+ "id", &rb_option_id,
1313
+ NULL);
1314
+ if (!(NIL_P(rb_option_id) || RVAL2CBOOL(rb_option_id))) {
1315
+ rb_raise(rb_eArgError, ":id options must be true or nil: %s: %s",
1316
+ rb_grn_inspect(rb_option_id),
1317
+ rb_grn_inspect(rb_ary_new3(2,
1318
+ self, rb_ary_new4(argc, argv))));
1319
+ }
1320
+ }
1321
+
1322
+ return rb_grn_table_set_value(self, rb_id, rb_value);
1323
+ }
1324
+
1325
+ VALUE
1326
+ rb_grn_table_get_column_value_raw (VALUE self, grn_id id, VALUE rb_name)
1327
+ {
1328
+ VALUE rb_column;
1329
+
1330
+ rb_column = rb_grn_table_get_column_surely(self, rb_name);
1331
+
1332
+ /* TODO: improve speed. */
1333
+ return rb_funcall(rb_column, id_array_reference, 1, INT2NUM(id));
1334
+ }
1335
+
1336
+ VALUE
1337
+ rb_grn_table_get_column_value (VALUE self, VALUE rb_id, VALUE rb_name)
1338
+ {
1339
+ return rb_grn_table_get_column_value_raw(self, NUM2INT(rb_id), rb_name);
1340
+ }
1341
+
1342
+ /*
1343
+ * Document-method: column_value
1344
+ *
1345
+ * call-seq:
1346
+ * table.column_value(id, name) -> 値
1347
+ * table.column_value(id, name, :id => true) -> 値
1348
+ *
1349
+ * _table_の_id_に対応するカラム_name_の値を返す。
1350
+ *
1351
+ * <tt>:id => true</tt>が指定できるのは利便性のため。
1352
+ * Groonga::ArrayでもGroonga::HashやGroonga::PatriciaTrieと
1353
+ * 同じ引数で動くようになる。
1354
+ */
1355
+ static VALUE
1356
+ rb_grn_table_get_column_value_convenience (int argc, VALUE *argv, VALUE self)
1357
+ {
1358
+ VALUE rb_id, rb_name, rb_options;
1359
+
1360
+ rb_scan_args(argc, argv, "21", &rb_id, &rb_name, &rb_options);
1361
+ if (!NIL_P(rb_options)) {
1362
+ VALUE rb_option_id;
1363
+ rb_grn_scan_options(rb_options,
1364
+ "id", &rb_option_id,
1365
+ NULL);
1366
+ if (!(NIL_P(rb_option_id) || RVAL2CBOOL(rb_option_id))) {
1367
+ rb_raise(rb_eArgError, ":id options must be true or nil: %s: %s",
1368
+ rb_grn_inspect(rb_option_id),
1369
+ rb_grn_inspect(rb_ary_new3(2,
1370
+ self,
1371
+ rb_ary_new4(argc, argv))));
1372
+ }
1373
+ }
1374
+
1375
+ return rb_grn_table_get_column_value(self, rb_id, rb_name);
1376
+ }
1377
+
1378
+ VALUE
1379
+ rb_grn_table_set_column_value_raw (VALUE self, grn_id id,
1380
+ VALUE rb_name, VALUE rb_value)
1381
+ {
1382
+ VALUE rb_column;
1383
+
1384
+ rb_column = rb_grn_table_get_column_surely(self, rb_name);
1385
+
1386
+ /* TODO: improve speed. */
1387
+ return rb_funcall(rb_column, id_array_set, 2, INT2NUM(id), rb_value);
1388
+ }
1389
+
1390
+ VALUE
1391
+ rb_grn_table_set_column_value (VALUE self, VALUE rb_id,
1392
+ VALUE rb_name, VALUE rb_value)
1393
+ {
1394
+ return rb_grn_table_set_column_value_raw(self, NUM2INT(rb_id),
1395
+ rb_name, rb_value);
1396
+ }
1397
+
1398
+ /*
1399
+ * Document-method: set_column_value
1400
+ *
1401
+ * call-seq:
1402
+ * table.set_column_value(id, name, value)
1403
+ * table.set_column_value(id, name, value, :id => true)
1404
+ *
1405
+ * _table_の_id_に対応するカラム_name_の値として_value_設定す
1406
+ * る。既存の値は上書きされる。
1407
+ *
1408
+ * <tt>:id => true</tt>が指定できるのは利便性のため。
1409
+ * Groonga::ArrayでもGroonga::HashやGroonga::PatriciaTrieと
1410
+ * 同じ引数で動くようになる。
1411
+ */
1412
+ static VALUE
1413
+ rb_grn_table_set_column_value_convenience (int argc, VALUE *argv, VALUE self)
1414
+ {
1415
+ VALUE rb_id, rb_name, rb_value, rb_options;
1416
+
1417
+ rb_scan_args(argc, argv, "31", &rb_id, &rb_name, &rb_value, &rb_options);
1418
+ if (!NIL_P(rb_options)) {
1419
+ VALUE rb_option_id;
1420
+ rb_grn_scan_options(rb_options,
1421
+ "id", &rb_option_id,
1422
+ NULL);
1423
+ if (!(NIL_P(rb_option_id) || RVAL2CBOOL(rb_option_id))) {
1424
+ rb_raise(rb_eArgError, ":id options must be true or nil: %s: %s",
1425
+ rb_grn_inspect(rb_option_id),
1426
+ rb_grn_inspect(rb_ary_new3(2,
1427
+ self,
1428
+ rb_ary_new4(argc, argv))));
1429
+ }
1430
+ }
1431
+
1432
+ return rb_grn_table_set_column_value(self, rb_id, rb_name, rb_value);
1433
+ }
1434
+
1435
+ /*
1436
+ * Document-method: unlock
1437
+ *
1438
+ * call-seq:
1439
+ * table.unlock(options={})
1440
+ *
1441
+ * _table_のロックを解除する。
1442
+ *
1443
+ * 利用可能なオプションは以下の通り。
1444
+ *
1445
+ * [_:id_]
1446
+ * _:id_で指定したレコードのロックを解除する。(注:
1447
+ * groonga側が未実装のため、現在は無視される)
1448
+ */
1449
+ static VALUE
1450
+ rb_grn_table_unlock (int argc, VALUE *argv, VALUE self)
1451
+ {
1452
+ grn_id id = GRN_ID_NIL;
1453
+ grn_ctx *context;
1454
+ grn_obj *table;
1455
+ grn_rc rc;
1456
+ VALUE options, rb_id;
1457
+
1458
+ rb_scan_args(argc, argv, "01", &options);
1459
+
1460
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1461
+ NULL, NULL,
1462
+ NULL, NULL, NULL,
1463
+ NULL);
1464
+
1465
+ rb_grn_scan_options(options,
1466
+ "id", &rb_id,
1467
+ NULL);
1468
+
1469
+ if (!NIL_P(rb_id))
1470
+ id = NUM2UINT(rb_id);
1471
+
1472
+ rc = grn_obj_unlock(context, table, id);
1473
+ rb_grn_context_check(context, self);
1474
+ rb_grn_rc_check(rc, self);
1475
+
1476
+ return Qnil;
1477
+ }
1478
+
1479
+ static VALUE
1480
+ rb_grn_table_unlock_ensure (VALUE self)
1481
+ {
1482
+ return rb_grn_table_unlock(0, NULL, self);
1483
+ }
1484
+
1485
+ /*
1486
+ * Document-method: lock
1487
+ *
1488
+ * call-seq:
1489
+ * table.lock(options={})
1490
+ * table.lock(options={}) {...}
1491
+ *
1492
+ * _table_をロックする。ロックに失敗した場合は
1493
+ * Groonga::ResourceDeadlockAvoided例外が発生する。
1494
+ *
1495
+ * ブロックを指定した場合はブロックを抜けたときにunlockする。
1496
+ *
1497
+ * 利用可能なオプションは以下の通り。
1498
+ *
1499
+ * [_:timeout_]
1500
+ * ロックを獲得できなかった場合は_:timeout_秒間ロックの獲
1501
+ * 得を試みる。_:timeout_秒以内にロックを獲得できなかった
1502
+ * 場合は例外が発生する。
1503
+ * [_:id_]
1504
+ * _:id_で指定したレコードをロックする。(注: groonga側が
1505
+ * 未実装のため、現在は無視される)
1506
+ */
1507
+ static VALUE
1508
+ rb_grn_table_lock (int argc, VALUE *argv, VALUE self)
1509
+ {
1510
+ grn_id id = GRN_ID_NIL;
1511
+ grn_ctx *context;
1512
+ grn_obj *table;
1513
+ int timeout = 0;
1514
+ grn_rc rc;
1515
+ VALUE options, rb_timeout, rb_id;
1516
+
1517
+ rb_scan_args(argc, argv, "01", &options);
1518
+
1519
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1520
+ NULL, NULL,
1521
+ NULL, NULL, NULL,
1522
+ NULL);
1523
+
1524
+ rb_grn_scan_options(options,
1525
+ "timeout", &rb_timeout,
1526
+ "id", &rb_id,
1527
+ NULL);
1528
+
1529
+ if (!NIL_P(rb_timeout))
1530
+ timeout = NUM2UINT(rb_timeout);
1531
+
1532
+ if (!NIL_P(rb_id))
1533
+ id = NUM2UINT(rb_id);
1534
+
1535
+ rc = grn_obj_lock(context, table, id, timeout);
1536
+ rb_grn_context_check(context, self);
1537
+ rb_grn_rc_check(rc, self);
1538
+
1539
+ if (rb_block_given_p()) {
1540
+ return rb_ensure(rb_yield, Qnil, rb_grn_table_unlock_ensure, self);
1541
+ } else {
1542
+ return Qnil;
1543
+ }
1544
+ }
1545
+
1546
+ /*
1547
+ * Document-method: clear_lock
1548
+ *
1549
+ * call-seq:
1550
+ * table.clear_lock(options={})
1551
+ *
1552
+ * _table_のロックを強制的に解除する。
1553
+ *
1554
+ * 利用可能なオプションは以下の通り。
1555
+ *
1556
+ * [_:id_]
1557
+ * _:id_で指定したレコードのロックを強制的に解除する。
1558
+ * (注: groonga側が未実装のため、現在は無視される。実装さ
1559
+ * れるのではないかと思っているが、実装されないかもしれな
1560
+ * い。)
1561
+ */
1562
+ static VALUE
1563
+ rb_grn_table_clear_lock (int argc, VALUE *argv, VALUE self)
1564
+ {
1565
+ grn_id id = GRN_ID_NIL;
1566
+ grn_ctx *context;
1567
+ grn_obj *table;
1568
+ VALUE options, rb_id;
1569
+
1570
+ rb_scan_args(argc, argv, "01", &options);
1571
+
1572
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1573
+ NULL, NULL,
1574
+ NULL, NULL, NULL,
1575
+ NULL);
1576
+
1577
+ rb_grn_scan_options(options,
1578
+ "id", &rb_id,
1579
+ NULL);
1580
+
1581
+ if (!NIL_P(rb_id))
1582
+ id = NUM2UINT(rb_id);
1583
+
1584
+ grn_obj_clear_lock(context, table);
1585
+
1586
+ return Qnil;
1587
+ }
1588
+
1589
+ /*
1590
+ * Document-method: locked?
1591
+ *
1592
+ * call-seq:
1593
+ * table.locked?(options={})
1594
+ *
1595
+ * _table_がロックされていれば+true+を返す。
1596
+ *
1597
+ * 利用可能なオプションは以下の通り。
1598
+ *
1599
+ * [_:id_]
1600
+ * _:id_で指定したレコードがロックされていれば+true+を返す。
1601
+ * (注: groonga側が未実装のため、現在は無視される。実装さ
1602
+ * れるのではないかと思っているが、実装されないかもしれな
1603
+ * い。)
1604
+ */
1605
+ static VALUE
1606
+ rb_grn_table_is_locked (int argc, VALUE *argv, VALUE self)
1607
+ {
1608
+ grn_id id = GRN_ID_NIL;
1609
+ grn_ctx *context;
1610
+ grn_obj *table;
1611
+ VALUE options, rb_id;
1612
+
1613
+ rb_scan_args(argc, argv, "01", &options);
1614
+
1615
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1616
+ NULL, NULL,
1617
+ NULL, NULL, NULL,
1618
+ NULL);
1619
+
1620
+ rb_grn_scan_options(options,
1621
+ "id", &rb_id,
1622
+ NULL);
1623
+
1624
+ if (!NIL_P(rb_id))
1625
+ id = NUM2UINT(rb_id);
1626
+
1627
+ return CBOOL2RVAL(grn_obj_is_locked(context, table));
1628
+ }
1629
+
1630
+ /*
1631
+ * call-seq:
1632
+ * table.select(options) {|record| ...} -> Groonga::Hash
1633
+ * table.select(query, options) -> Groonga::Hash
1634
+ * table.select(expression, options) -> Groonga::Hash
1635
+ *
1636
+ * _table_からブロックまたは文字列で指定した条件にマッチする
1637
+ * レコードを返す。返されたテーブルには+expression+という特
1638
+ * 異メソッドがあり、指定した条件を表している
1639
+ * Groonga::Expressionを取得できる。
1640
+ * Groonga::Expression#snippetを使うことにより、指定した条件
1641
+ * 用のスニペットを簡単に生成できる。
1642
+ *
1643
+ * results = table.select do |record|
1644
+ * record["description"] =~ "groonga"
1645
+ * end
1646
+ * snippet = results.expression.snippet([["<em>", "</em>"]])
1647
+ * results.each do |record|
1648
+ * puts "#{record['name']}の説明文の中で「groonga」が含まれる部分"
1649
+ * snippet.execute(record["description"].each do |snippet|
1650
+ * puts "---"
1651
+ * puts "#{snippet}..."
1652
+ * puts "---"
1653
+ * end
1654
+ * end
1655
+ *
1656
+ * 出力例
1657
+ * Ruby/groongaの説明文の中で「groonga」が含まれる部分
1658
+ * ---
1659
+ * Ruby/<em>groonga</em>は<em>groonga</em>のいわゆるDB-APIの層の...
1660
+ * ---
1661
+ *
1662
+ * _query_には「[カラム名]:[演算子][値]」という書式で条件を
1663
+ * 指定する。演算子は以下の通り。
1664
+ *
1665
+ * [なし]
1666
+ * [カラム値] == [値]
1667
+ * [<tt>!</tt>]
1668
+ * [カラム値] != [値]
1669
+ * [<tt><</tt>]
1670
+ * [カラム値] < [値]
1671
+ * [<tt>></tt>]
1672
+ * [カラム値] > [値]
1673
+ * [<tt><=</tt>]
1674
+ * [カラム値] <= [値]
1675
+ * [<tt>>=</tt>]
1676
+ * [カラム値] >= [値]
1677
+ * [<tt>@</tt>]
1678
+ * [カラム値]が[値]を含んでいるかどうか
1679
+ *
1680
+ * 例:
1681
+ * "name:daijiro" # "name"カラムの値が"daijiro"のレコードにマッチ
1682
+ * "description:@groonga" # "description"カラムが
1683
+ * # "groonga"を含んでいるレコードにマッチ
1684
+ *
1685
+ * _expression_には既に作成済みのGroonga::Expressionを渡す
1686
+ *
1687
+ * ブロックで条件を指定する場合は
1688
+ * Groonga::RecordExpressionBuilderを参照。
1689
+ *
1690
+ * _options_に指定可能な値は以下の通り。
1691
+ *
1692
+ * [+:default_column+]
1693
+ * "column_name:hoge"ではなく"hoge"のようにcolumn_nameが指
1694
+ * 定されない条件の検索対象となるカラムを指定する。
1695
+ *
1696
+ * [+:operator+]
1697
+ * マッチしたレコードをどのように扱うか。指定可能な値は以
1698
+ * 下の通り。省略した場合はGroonga::Operation::OR。
1699
+ *
1700
+ * [Groonga::Operation::OR]
1701
+ * マッチしたレコードを追加。すでにレコードが追加され
1702
+ * ている場合は何もしない。
1703
+ * [Groonga::Operation::AND]
1704
+ * マッチしたレコードのスコアを増加。マッチしなかった
1705
+ * レコードを削除。
1706
+ * [Groonga::Operation::BUT]
1707
+ * マッチしたレコードを削除。
1708
+ * [Groonga::Operation::ADJUST]
1709
+ * マッチしたレコードのスコアを増加。
1710
+ *
1711
+ * [+:result+]
1712
+ * 検索結果を格納するテーブル。マッチしたレコードが追加さ
1713
+ * れていく。省略した場合は新しくテーブルを作成して返す。
1714
+ *
1715
+ * [+:name+]
1716
+ * 条件の名前。省略した場合は名前を付けない。
1717
+ *
1718
+ * [+:syntax+]
1719
+ * _query_の構文。省略した場合は+:query+。
1720
+ *
1721
+ * 参考: Groonga::Expression#parse.
1722
+ *
1723
+ * [+:allow_pragma+]
1724
+ * query構文時にプラグマを利用するかどうか。省略した場合は
1725
+ * 利用する。
1726
+ *
1727
+ * 参考: Groonga::Expression#parse.
1728
+ *
1729
+ * [+:allow_column+]
1730
+ * query構文時にカラム指定を利用するかどうか。省略した場合
1731
+ * は利用する。
1732
+ *
1733
+ * 参考: Groonga::Expression#parse.
1734
+ *
1735
+ * [+:allow_update+]
1736
+ * script構文時に更新操作を利用するかどうか。省略した場合
1737
+ * は利用する。
1738
+ *
1739
+ * 参考: Groonga::Expression#parse.
1740
+ */
1741
+ static VALUE
1742
+ rb_grn_table_select (int argc, VALUE *argv, VALUE self)
1743
+ {
1744
+ grn_ctx *context;
1745
+ grn_obj *table, *result, *expression;
1746
+ grn_operator operator = GRN_OP_OR;
1747
+ VALUE rb_query = Qnil, condition_or_options, options;
1748
+ VALUE rb_name, rb_operator, rb_result, rb_syntax;
1749
+ VALUE rb_allow_pragma, rb_allow_column, rb_allow_update;
1750
+ VALUE rb_default_column;
1751
+ VALUE rb_expression = Qnil, builder;
1752
+
1753
+ rb_scan_args(argc, argv, "02", &condition_or_options, &options);
1754
+
1755
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1756
+ NULL, NULL,
1757
+ NULL, NULL, NULL,
1758
+ NULL);
1759
+
1760
+ if (RVAL2CBOOL(rb_obj_is_kind_of(condition_or_options, rb_cString))) {
1761
+ rb_query = condition_or_options;
1762
+ } else if (RVAL2CBOOL(rb_obj_is_kind_of(condition_or_options,
1763
+ rb_cGrnExpression))) {
1764
+ rb_expression = condition_or_options;
1765
+ } else {
1766
+ if (!NIL_P(options))
1767
+ rb_raise(rb_eArgError,
1768
+ "should be [query_string, option_hash], "
1769
+ "[expression, opion_hash] "
1770
+ "or [option_hash]: %s",
1771
+ rb_grn_inspect(rb_ary_new4(argc, argv)));
1772
+ options = condition_or_options;
1773
+ }
1774
+
1775
+ rb_grn_scan_options(options,
1776
+ "operator", &rb_operator,
1777
+ "result", &rb_result,
1778
+ "name", &rb_name,
1779
+ "syntax", &rb_syntax,
1780
+ "allow_pragma", &rb_allow_pragma,
1781
+ "allow_column", &rb_allow_column,
1782
+ "allow_update", &rb_allow_update,
1783
+ "default_column", &rb_default_column,
1784
+ NULL);
1785
+
1786
+ if (!NIL_P(rb_operator))
1787
+ operator = NUM2INT(rb_operator);
1788
+
1789
+ if (NIL_P(rb_result)) {
1790
+ result = grn_table_create(context, NULL, 0, NULL,
1791
+ GRN_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
1792
+ table,
1793
+ 0);
1794
+ rb_result = GRNTABLE2RVAL(context, result, RB_GRN_TRUE);
1795
+ } else {
1796
+ result = RVAL2GRNTABLE(rb_result, &context);
1797
+ }
1798
+
1799
+ if (NIL_P(rb_expression)) {
1800
+ builder = rb_grn_record_expression_builder_new(self, rb_name);
1801
+ rb_funcall(builder, rb_intern("query="), 1, rb_query);
1802
+ rb_funcall(builder, rb_intern("syntax="), 1, rb_syntax);
1803
+ rb_funcall(builder, rb_intern("allow_pragma="), 1, rb_allow_pragma);
1804
+ rb_funcall(builder, rb_intern("allow_column="), 1, rb_allow_column);
1805
+ rb_funcall(builder, rb_intern("allow_update="), 1, rb_allow_update);
1806
+ rb_funcall(builder, rb_intern("default_column="), 1, rb_default_column);
1807
+ rb_expression = rb_grn_record_expression_builder_build(builder);
1808
+ }
1809
+ rb_grn_object_deconstruct(RB_GRN_OBJECT(DATA_PTR(rb_expression)),
1810
+ &expression, NULL,
1811
+ NULL, NULL, NULL, NULL);
1812
+
1813
+ grn_table_select(context, table, expression, result, operator);
1814
+ rb_grn_context_check(context, self);
1815
+
1816
+ rb_attr(rb_singleton_class(rb_result),
1817
+ rb_intern("expression"),
1818
+ RB_GRN_TRUE, RB_GRN_FALSE, RB_GRN_FALSE);
1819
+ rb_iv_set(rb_result, "@expression", rb_expression);
1820
+
1821
+ return rb_result;
1822
+ }
1823
+
1824
+ static VALUE
1825
+ rb_grn_table_set_operation_bang (VALUE self, VALUE rb_other,
1826
+ grn_operator operator)
1827
+ {
1828
+ grn_ctx *context;
1829
+ grn_obj *table, *other;
1830
+ grn_rc rc;
1831
+
1832
+ rb_grn_table_deconstruct(SELF(self), &table, &context,
1833
+ NULL, NULL,
1834
+ NULL, NULL, NULL,
1835
+ NULL);
1836
+ rb_grn_table_deconstruct(SELF(rb_other), &other, NULL,
1837
+ NULL, NULL,
1838
+ NULL, NULL, NULL,
1839
+ NULL);
1840
+
1841
+ rc = grn_table_setoperation(context, table, other, table, operator);
1842
+ rb_grn_context_check(context, self);
1843
+ rb_grn_rc_check(rc, self);
1844
+
1845
+ return self;
1846
+ }
1847
+
1848
+ /*
1849
+ * call-seq:
1850
+ * table.union!(other) -> Groonga::Table
1851
+ *
1852
+ * キーを比較し、_table_には登録されていない_other_のレコー
1853
+ * ドを_table_に作成する。
1854
+ *
1855
+ */
1856
+ static VALUE
1857
+ rb_grn_table_union_bang (VALUE self, VALUE rb_other)
1858
+ {
1859
+ return rb_grn_table_set_operation_bang(self, rb_other, GRN_OP_OR);
1860
+ }
1861
+
1862
+
1863
+ /*
1864
+ * call-seq:
1865
+ * table.intersection!(other) -> Groonga::Table
1866
+ *
1867
+ * キーを比較し、_other_には登録されていないレコードを
1868
+ * _table_から削除する。
1869
+ *
1870
+ */
1871
+ static VALUE
1872
+ rb_grn_table_intersection_bang (VALUE self, VALUE rb_other)
1873
+ {
1874
+ return rb_grn_table_set_operation_bang(self, rb_other, GRN_OP_AND);
1875
+ }
1876
+
1877
+ /*
1878
+ * call-seq:
1879
+ * table.difference!(other) -> Groonga::Table
1880
+ *
1881
+ * キーを比較し、_other_にも登録されているレコードを_table_
1882
+ * から削除する。
1883
+ *
1884
+ */
1885
+ static VALUE
1886
+ rb_grn_table_difference_bang (VALUE self, VALUE rb_other)
1887
+ {
1888
+ return rb_grn_table_set_operation_bang(self, rb_other, GRN_OP_BUT);
1889
+ }
1890
+
1891
+ /*
1892
+ * call-seq:
1893
+ * table.merge!(other) -> Groonga::Table
1894
+ *
1895
+ * キーを比較し、_other_にも登録されている_table_のレコード
1896
+ * のスコアを_other_のスコアと同値にする。
1897
+ *
1898
+ */
1899
+ static VALUE
1900
+ rb_grn_table_merge_bang (VALUE self, VALUE rb_other)
1901
+ {
1902
+ return rb_grn_table_set_operation_bang(self, rb_other, GRN_OP_ADJUST);
1903
+ }
1904
+
1905
+ void
1906
+ rb_grn_init_table (VALUE mGrn)
1907
+ {
1908
+ id_array_reference = rb_intern("[]");
1909
+ id_array_set = rb_intern("[]=");
1910
+
1911
+ rb_cGrnTable = rb_define_class_under(mGrn, "Table", rb_cGrnObject);
1912
+ rb_define_alloc_func(rb_cGrnTable, rb_grn_table_alloc);
1913
+
1914
+ rb_include_module(rb_cGrnTable, rb_mEnumerable);
1915
+
1916
+ rb_define_method(rb_cGrnTable, "initialize", rb_grn_table_initialize, 0);
1917
+
1918
+ rb_define_method(rb_cGrnTable, "inspect", rb_grn_table_inspect, 0);
1919
+
1920
+ rb_define_method(rb_cGrnTable, "define_column",
1921
+ rb_grn_table_define_column, -1);
1922
+ rb_define_method(rb_cGrnTable, "define_index_column",
1923
+ rb_grn_table_define_index_column, -1);
1924
+ rb_define_method(rb_cGrnTable, "column",
1925
+ rb_grn_table_get_column, 1);
1926
+ rb_define_method(rb_cGrnTable, "columns",
1927
+ rb_grn_table_get_columns, -1);
1928
+ rb_define_method(rb_cGrnTable, "have_column?",
1929
+ rb_grn_table_have_column, 1);
1930
+
1931
+ rb_define_method(rb_cGrnTable, "open_cursor", rb_grn_table_open_cursor, -1);
1932
+ rb_define_method(rb_cGrnTable, "records", rb_grn_table_get_records, -1);
1933
+
1934
+ rb_define_method(rb_cGrnTable, "size", rb_grn_table_get_size, 0);
1935
+ rb_define_method(rb_cGrnTable, "empty?", rb_grn_table_empty_p, 0);
1936
+ rb_define_method(rb_cGrnTable, "truncate", rb_grn_table_truncate, 0);
1937
+
1938
+ rb_define_method(rb_cGrnTable, "each", rb_grn_table_each, 0);
1939
+
1940
+ rb_define_method(rb_cGrnTable, "delete", rb_grn_table_delete, 1);
1941
+
1942
+ rb_define_method(rb_cGrnTable, "sort", rb_grn_table_sort, -1);
1943
+ rb_define_method(rb_cGrnTable, "group", rb_grn_table_group, -1);
1944
+
1945
+ rb_define_method(rb_cGrnTable, "[]", rb_grn_table_array_reference, 1);
1946
+ rb_undef_method(rb_cGrnTable, "[]=");
1947
+
1948
+ rb_define_method(rb_cGrnTable, "value",
1949
+ rb_grn_table_get_value_convenience, -1);
1950
+ rb_define_method(rb_cGrnTable, "set_value",
1951
+ rb_grn_table_set_value_convenience, -1);
1952
+ rb_define_method(rb_cGrnTable, "column_value",
1953
+ rb_grn_table_get_column_value_convenience, -1);
1954
+ rb_define_method(rb_cGrnTable, "set_column_value",
1955
+ rb_grn_table_set_column_value_convenience, -1);
1956
+
1957
+ rb_define_method(rb_cGrnTable, "lock", rb_grn_table_lock, -1);
1958
+ rb_define_method(rb_cGrnTable, "unlock", rb_grn_table_unlock, -1);
1959
+ rb_define_method(rb_cGrnTable, "clear_lock", rb_grn_table_clear_lock, -1);
1960
+ rb_define_method(rb_cGrnTable, "locked?", rb_grn_table_is_locked, -1);
1961
+
1962
+ rb_define_method(rb_cGrnTable, "select", rb_grn_table_select, -1);
1963
+
1964
+ rb_define_method(rb_cGrnTable, "union!", rb_grn_table_union_bang, 1);
1965
+ rb_define_method(rb_cGrnTable, "intersection!",
1966
+ rb_grn_table_intersection_bang, 1);
1967
+ rb_define_method(rb_cGrnTable, "difference!",
1968
+ rb_grn_table_difference_bang, 1);
1969
+ rb_define_method(rb_cGrnTable, "merge!",
1970
+ rb_grn_table_merge_bang, 1);
1971
+
1972
+ rb_grn_init_table_key_support(mGrn);
1973
+ rb_grn_init_array(mGrn);
1974
+ rb_grn_init_hash(mGrn);
1975
+ rb_grn_init_patricia_trie(mGrn);
1976
+ rb_grn_init_view(mGrn);
1977
+ }