1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2015 Brazil
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "../grn_ctx_impl.h"
20#include "../grn_ii.h"
21#include "../grn_db.h"
22
23#ifdef GRN_WITH_MRUBY
24#include <mruby.h>
25#include <mruby/class.h>
26#include <mruby/data.h>
27#include <mruby/string.h>
28#include <mruby/hash.h>
29#include <mruby/variable.h>
30
31#include "mrb_ctx.h"
32#include "mrb_index_cursor.h"
33#include "mrb_converter.h"
34#include "mrb_options.h"
35
36static struct mrb_data_type mrb_grn_index_cursor_type = {
37 "Groonga::IndexCursor",
38 NULL
39};
40
41static mrb_value
42mrb_grn_index_cursor_class_open_raw(mrb_state *mrb, mrb_value klass)
43{
44 grn_ctx *ctx = (grn_ctx *)mrb->ud;
45 mrb_value mrb_table_cursor;
46 mrb_value mrb_index;
47 mrb_value mrb_options = mrb_nil_value();
48 grn_obj *index_cursor;
49 grn_table_cursor *table_cursor;
50 grn_obj *index;
51 grn_id rid_min = GRN_ID_NIL;
52 grn_id rid_max = GRN_ID_MAX;
53 int flags = 0;
54 mrb_value mrb_index_cursor;
55
56 mrb_get_args(mrb, "oo|H", &mrb_table_cursor, &mrb_index, &mrb_options);
57
58 table_cursor = DATA_PTR(mrb_table_cursor);
59 index = DATA_PTR(mrb_index);
60 if (!mrb_nil_p(mrb_options)) {
61 /* TODO */
62 }
63 index_cursor = grn_index_cursor_open(ctx, table_cursor, index,
64 rid_min, rid_max, flags);
65 grn_mrb_ctx_check(mrb);
66
67 mrb_index_cursor = mrb_funcall(mrb, klass, "new", 1,
68 mrb_cptr_value(mrb, index_cursor));
69 mrb_iv_set(mrb, mrb_index_cursor, mrb_intern_lit(mrb, "@index"), mrb_index);
70 return mrb_index_cursor;
71}
72
73static mrb_value
74mrb_grn_index_cursor_initialize(mrb_state *mrb, mrb_value self)
75{
76 mrb_value mrb_index_cursor_ptr;
77
78 mrb_get_args(mrb, "o", &mrb_index_cursor_ptr);
79 DATA_TYPE(self) = &mrb_grn_index_cursor_type;
80 DATA_PTR(self) = mrb_cptr(mrb_index_cursor_ptr);
81
82 return self;
83}
84
85static mrb_value
86mrb_grn_index_cursor_close(mrb_state *mrb, mrb_value self)
87{
88 grn_ctx *ctx = (grn_ctx *)mrb->ud;
89 grn_obj *index_cursor;
90
91 index_cursor = DATA_PTR(self);
92 if (index_cursor) {
93 DATA_PTR(self) = NULL;
94 grn_obj_close(ctx, index_cursor);
95 grn_mrb_ctx_check(mrb);
96 }
97
98 return mrb_nil_value();
99}
100
101static mrb_value
102mrb_grn_index_cursor_count(mrb_state *mrb, mrb_value self)
103{
104 grn_ctx *ctx = (grn_ctx *)mrb->ud;
105 grn_id term_id;
106 int n_records = 0;
107
108 while (grn_index_cursor_next(ctx, DATA_PTR(self), &term_id)) {
109 n_records++;
110 }
111
112 return mrb_fixnum_value(n_records);
113}
114
115static mrb_value
116mrb_grn_index_cursor_select(mrb_state *mrb, mrb_value self)
117{
118 grn_ctx *ctx = (grn_ctx *)mrb->ud;
119 mrb_value mrb_result_set;
120 mrb_value mrb_options;
121 grn_obj *index_cursor;
122 grn_obj *expr = NULL;
123 grn_obj *expr_variable = NULL;
124 int offset = 0;
125 int limit = 10;
126 int max_n_unmatched_records = -1;
127 int n_matched_records = 0;
128 int n_unmatched_records = 0;
129 mrb_value mrb_index;
130 grn_obj *index;
131 grn_obj *lexicon;
132 grn_obj *data_table;
133 grn_hash *result_set;
134 grn_posting *posting;
135 grn_id term_id;
136 grn_operator op = GRN_OP_OR;
137
138 mrb_get_args(mrb, "o|H", &mrb_result_set, &mrb_options);
139
140 index_cursor = DATA_PTR(self);
141 result_set = DATA_PTR(mrb_result_set);
142
143 if (!mrb_nil_p(mrb_options)) {
144 mrb_value mrb_expr;
145 mrb_value mrb_offset;
146 mrb_value mrb_limit;
147 mrb_value mrb_max_n_unmatched_records;
148
149 mrb_expr = grn_mrb_options_get_lit(mrb, mrb_options, "expression");
150 if (!mrb_nil_p(mrb_expr)) {
151 expr = DATA_PTR(mrb_expr);
152 expr_variable = grn_expr_get_var_by_offset(ctx, expr, 0);
153 }
154
155 mrb_offset = grn_mrb_options_get_lit(mrb, mrb_options, "offset");
156 if (!mrb_nil_p(mrb_offset)) {
157 offset = mrb_fixnum(mrb_offset);
158 }
159
160 mrb_limit = grn_mrb_options_get_lit(mrb, mrb_options, "limit");
161 if (!mrb_nil_p(mrb_limit)) {
162 limit = mrb_fixnum(mrb_limit);
163 }
164
165 mrb_max_n_unmatched_records =
166 grn_mrb_options_get_lit(mrb, mrb_options, "max_n_unmatched_records");
167 if (!mrb_nil_p(mrb_max_n_unmatched_records)) {
168 max_n_unmatched_records = mrb_fixnum(mrb_max_n_unmatched_records);
169 }
170 }
171
172 if (limit <= 0) {
173 return mrb_fixnum_value(n_matched_records);
174 }
175
176 mrb_index = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@index"));
177 index = DATA_PTR(mrb_index);
178 lexicon = ((grn_ii *)index)->lexicon;
179 data_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, index));
180
181 if (max_n_unmatched_records < 0) {
182 max_n_unmatched_records = INT32_MAX;
183 }
184 while ((posting = grn_index_cursor_next(ctx, index_cursor, &term_id))) {
185 if (expr) {
186 grn_bool matched_raw = GRN_FALSE;
187 grn_obj *matched;
188
189 GRN_RECORD_SET(ctx, expr_variable, posting->rid);
190 matched = grn_expr_exec(ctx, expr, 0);
191 if (matched) {
192 matched_raw = grn_obj_is_true(ctx, matched);
193 } else {
194 grn_mrb_ctx_check(mrb);
195 }
196
197 if (!matched_raw) {
198 n_unmatched_records++;
199 if (n_unmatched_records > max_n_unmatched_records) {
200 return mrb_fixnum_value(-1);
201 }
202 continue;
203 }
204 }
205 n_matched_records++;
206 if (offset > 0) {
207 offset--;
208 continue;
209 }
210 grn_ii_posting_add(ctx, posting, result_set, op);
211 limit--;
212 if (limit == 0) {
213 break;
214 }
215 }
216 grn_ii_resolve_sel_and(ctx, result_set, op);
217
218 return mrb_fixnum_value(n_matched_records);
219}
220
221void
222grn_mrb_index_cursor_init(grn_ctx *ctx)
223{
224 grn_mrb_data *data = &(ctx->impl->mrb);
225 mrb_state *mrb = data->state;
226 struct RClass *module = data->module;
227 struct RClass *klass;
228
229 klass = mrb_define_class_under(mrb, module, "IndexCursor", mrb->object_class);
230 MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
231
232 mrb_define_class_method(mrb, klass, "open_raw",
233 mrb_grn_index_cursor_class_open_raw,
234 MRB_ARGS_ARG(2, 1));
235
236 mrb_define_method(mrb, klass, "initialize",
237 mrb_grn_index_cursor_initialize, MRB_ARGS_REQ(1));
238 mrb_define_method(mrb, klass, "close",
239 mrb_grn_index_cursor_close, MRB_ARGS_NONE());
240 mrb_define_method(mrb, klass, "count",
241 mrb_grn_index_cursor_count, MRB_ARGS_NONE());
242 mrb_define_method(mrb, klass, "select",
243 mrb_grn_index_cursor_select, MRB_ARGS_ARG(1, 1));
244}
245#endif
246