rroonga 0.9.2-x86-mingw32

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 (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
+ }