1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2014-2017 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 <string.h> |
21 | |
22 | #ifdef GRN_WITH_MRUBY |
23 | #include <mruby.h> |
24 | #include <mruby/class.h> |
25 | #include <mruby/data.h> |
26 | #include <mruby/hash.h> |
27 | #include <mruby/array.h> |
28 | #include <mruby/string.h> |
29 | |
30 | #include "mrb_ctx.h" |
31 | #include "mrb_table.h" |
32 | #include "mrb_converter.h" |
33 | #include "mrb_options.h" |
34 | |
35 | static mrb_value |
36 | mrb_grn_table_array_reference(mrb_state *mrb, mrb_value self) |
37 | { |
38 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
39 | grn_obj *table; |
40 | grn_id key_domain_id; |
41 | mrb_value mrb_key; |
42 | grn_id record_id; |
43 | grn_mrb_value_to_raw_data_buffer buffer; |
44 | void *key; |
45 | unsigned int key_size; |
46 | |
47 | mrb_get_args(mrb, "o" , &mrb_key); |
48 | |
49 | table = DATA_PTR(self); |
50 | if (table->header.type == GRN_DB) { |
51 | key_domain_id = GRN_DB_SHORT_TEXT; |
52 | } else { |
53 | key_domain_id = table->header.domain; |
54 | } |
55 | |
56 | grn_mrb_value_to_raw_data_buffer_init(mrb, &buffer); |
57 | grn_mrb_value_to_raw_data(mrb, "key" , mrb_key, key_domain_id, |
58 | &buffer, &key, &key_size); |
59 | record_id = grn_table_get(ctx, table, key, key_size); |
60 | grn_mrb_value_to_raw_data_buffer_fin(mrb, &buffer); |
61 | |
62 | if (record_id == GRN_ID_NIL) { |
63 | return mrb_nil_value(); |
64 | } else { |
65 | return mrb_fixnum_value(record_id); |
66 | } |
67 | } |
68 | |
69 | static mrb_value |
70 | mrb_grn_table_is_id(mrb_state *mrb, mrb_value self) |
71 | { |
72 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
73 | grn_obj *table; |
74 | mrb_int mrb_record_id; |
75 | grn_id record_id; |
76 | grn_id real_record_id; |
77 | |
78 | mrb_get_args(mrb, "i" , &mrb_record_id); |
79 | |
80 | table = DATA_PTR(self); |
81 | record_id = (grn_id)mrb_record_id; |
82 | real_record_id = grn_table_at(ctx, table, record_id); |
83 | if (real_record_id == record_id) { |
84 | return mrb_true_value(); |
85 | } else { |
86 | return mrb_false_value(); |
87 | } |
88 | } |
89 | |
90 | static mrb_value |
91 | mrb_grn_table_find_column(mrb_state *mrb, mrb_value self) |
92 | { |
93 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
94 | grn_obj *table; |
95 | mrb_value mrb_column_name; |
96 | grn_obj *column; |
97 | |
98 | mrb_get_args(mrb, "o" , &mrb_column_name); |
99 | |
100 | table = DATA_PTR(self); |
101 | column = grn_obj_column(ctx, table, |
102 | RSTRING_PTR(mrb_column_name), |
103 | RSTRING_LEN(mrb_column_name)); |
104 | grn_mrb_ctx_check(mrb); |
105 | |
106 | return grn_mrb_value_from_grn_obj(mrb, column); |
107 | } |
108 | |
109 | static mrb_value |
110 | mrb_grn_table_get_column_ids(mrb_state *mrb, mrb_value self) |
111 | { |
112 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
113 | grn_obj *table; |
114 | grn_hash *columns; |
115 | int n_columns; |
116 | mrb_value mrb_column_ids; |
117 | |
118 | table = DATA_PTR(self); |
119 | columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, |
120 | GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY); |
121 | if (!columns) { |
122 | grn_mrb_ctx_check(mrb); |
123 | return mrb_ary_new(mrb); |
124 | } |
125 | |
126 | n_columns = grn_table_columns(ctx, table, "" , 0, (grn_obj *)columns); |
127 | mrb_column_ids = mrb_ary_new_capa(mrb, n_columns); |
128 | { |
129 | grn_id *key; |
130 | GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, { |
131 | mrb_ary_push(mrb, mrb_column_ids, mrb_fixnum_value(*key)); |
132 | }); |
133 | } |
134 | grn_hash_close(ctx, columns); |
135 | |
136 | grn_mrb_ctx_check(mrb); |
137 | |
138 | return mrb_column_ids; |
139 | } |
140 | |
141 | static mrb_value |
142 | mrb_grn_table_create_column(mrb_state *mrb, mrb_value self) |
143 | { |
144 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
145 | grn_obj *table; |
146 | mrb_value mrb_name; |
147 | mrb_int flags; |
148 | mrb_value mrb_type; |
149 | grn_obj *type; |
150 | grn_obj *column; |
151 | |
152 | mrb_get_args(mrb, "oio" , &mrb_name, &flags, &mrb_type); |
153 | |
154 | table = DATA_PTR(self); |
155 | type = DATA_PTR(mrb_type); |
156 | column = grn_column_create(ctx, table, |
157 | RSTRING_PTR(mrb_name), |
158 | RSTRING_LEN(mrb_name), |
159 | NULL, |
160 | flags, |
161 | type); |
162 | grn_mrb_ctx_check(mrb); |
163 | |
164 | return grn_mrb_value_from_grn_obj(mrb, column); |
165 | } |
166 | |
167 | static mrb_value |
168 | mrb_grn_table_is_locked(mrb_state *mrb, mrb_value self) |
169 | { |
170 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
171 | unsigned int is_locked; |
172 | |
173 | is_locked = grn_obj_is_locked(ctx, DATA_PTR(self)); |
174 | grn_mrb_ctx_check(mrb); |
175 | |
176 | return mrb_bool_value(is_locked != 0); |
177 | } |
178 | |
179 | static mrb_value |
180 | mrb_grn_table_get_size(mrb_state *mrb, mrb_value self) |
181 | { |
182 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
183 | unsigned int size; |
184 | |
185 | size = grn_table_size(ctx, DATA_PTR(self)); |
186 | grn_mrb_ctx_check(mrb); |
187 | |
188 | return mrb_fixnum_value(size); |
189 | } |
190 | |
191 | static mrb_value |
192 | mrb_grn_table_is_empty(mrb_state *mrb, mrb_value self) |
193 | { |
194 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
195 | unsigned int size; |
196 | |
197 | size = grn_table_size(ctx, DATA_PTR(self)); |
198 | grn_mrb_ctx_check(mrb); |
199 | |
200 | return mrb_bool_value(size == 0); |
201 | } |
202 | |
203 | static mrb_value |
204 | mrb_grn_table_select(mrb_state *mrb, mrb_value self) |
205 | { |
206 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
207 | grn_obj *table; |
208 | grn_obj *expr; |
209 | grn_obj *result = NULL; |
210 | grn_operator operator = GRN_OP_OR; |
211 | mrb_value mrb_expr; |
212 | mrb_value mrb_options = mrb_nil_value(); |
213 | |
214 | table = DATA_PTR(self); |
215 | mrb_get_args(mrb, "o|H" , &mrb_expr, &mrb_options); |
216 | |
217 | expr = DATA_PTR(mrb_expr); |
218 | |
219 | if (!mrb_nil_p(mrb_options)) { |
220 | mrb_value mrb_result; |
221 | mrb_value mrb_operator; |
222 | |
223 | mrb_result = grn_mrb_options_get_lit(mrb, mrb_options, "result" ); |
224 | if (!mrb_nil_p(mrb_result)) { |
225 | result = DATA_PTR(mrb_result); |
226 | } |
227 | |
228 | mrb_operator = grn_mrb_options_get_lit(mrb, mrb_options, "operator" ); |
229 | if (!mrb_nil_p(mrb_operator)) { |
230 | operator = mrb_fixnum(mrb_operator); |
231 | } |
232 | } |
233 | |
234 | result = grn_table_select(ctx, table, expr, result, operator); |
235 | if (ctx->rc != GRN_SUCCESS) { |
236 | grn_mrb_ctx_check(mrb); |
237 | } |
238 | |
239 | return grn_mrb_value_from_grn_obj(mrb, result); |
240 | } |
241 | |
242 | static mrb_value |
243 | mrb_grn_table_sort_raw(mrb_state *mrb, mrb_value self) |
244 | { |
245 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
246 | grn_obj *table; |
247 | mrb_value mrb_keys; |
248 | grn_table_sort_key *keys; |
249 | int i, n_keys; |
250 | mrb_int offset; |
251 | mrb_int limit; |
252 | mrb_value mrb_result; |
253 | grn_obj *result; |
254 | |
255 | table = DATA_PTR(self); |
256 | mrb_get_args(mrb, "oiio" , &mrb_keys, &offset, &limit, &mrb_result); |
257 | |
258 | mrb_keys = mrb_convert_type(mrb, mrb_keys, |
259 | MRB_TT_ARRAY, "Array" , "to_ary" ); |
260 | |
261 | n_keys = RARRAY_LEN(mrb_keys); |
262 | keys = GRN_MALLOCN(grn_table_sort_key, n_keys); |
263 | for (i = 0; i < n_keys; i++) { |
264 | grn_memcpy(&(keys[i]), |
265 | DATA_PTR(RARRAY_PTR(mrb_keys)[i]), |
266 | sizeof(grn_table_sort_key)); |
267 | } |
268 | result = DATA_PTR(mrb_result); |
269 | grn_table_sort(ctx, table, offset, limit, result, keys, n_keys); |
270 | GRN_FREE(keys); |
271 | grn_mrb_ctx_check(mrb); |
272 | |
273 | return mrb_result; |
274 | } |
275 | |
276 | static mrb_value |
277 | mrb_grn_table_group_raw(mrb_state *mrb, mrb_value self) |
278 | { |
279 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
280 | grn_obj *table; |
281 | mrb_value mrb_keys; |
282 | grn_table_sort_key *keys; |
283 | int i, n_keys; |
284 | mrb_value mrb_result; |
285 | grn_table_group_result *result; |
286 | |
287 | table = DATA_PTR(self); |
288 | mrb_get_args(mrb, "oo" , &mrb_keys, &mrb_result); |
289 | |
290 | mrb_keys = mrb_convert_type(mrb, mrb_keys, |
291 | MRB_TT_ARRAY, "Array" , "to_ary" ); |
292 | |
293 | n_keys = RARRAY_LEN(mrb_keys); |
294 | keys = GRN_MALLOCN(grn_table_sort_key, n_keys); |
295 | for (i = 0; i < n_keys; i++) { |
296 | grn_memcpy(&(keys[i]), |
297 | DATA_PTR(RARRAY_PTR(mrb_keys)[i]), |
298 | sizeof(grn_table_sort_key)); |
299 | } |
300 | result = DATA_PTR(mrb_result); |
301 | grn_table_group(ctx, table, keys, n_keys, result, 1); |
302 | GRN_FREE(keys); |
303 | grn_mrb_ctx_check(mrb); |
304 | |
305 | return mrb_result; |
306 | } |
307 | |
308 | static mrb_value |
309 | mrb_grn_table_delete(mrb_state *mrb, mrb_value self) |
310 | { |
311 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
312 | grn_obj *table; |
313 | mrb_value mrb_options; |
314 | mrb_value mrb_id; |
315 | mrb_value mrb_key; |
316 | mrb_value mrb_expression; |
317 | |
318 | table = DATA_PTR(self); |
319 | mrb_get_args(mrb, "H" , &mrb_options); |
320 | |
321 | mrb_id = grn_mrb_options_get_lit(mrb, mrb_options, "id" ); |
322 | if (!mrb_nil_p(mrb_id)) { |
323 | grn_table_delete_by_id(ctx, table, mrb_fixnum(mrb_id)); |
324 | grn_mrb_ctx_check(mrb); |
325 | return mrb_nil_value(); |
326 | } |
327 | |
328 | mrb_key = grn_mrb_options_get_lit(mrb, mrb_options, "key" ); |
329 | if (!mrb_nil_p(mrb_key)) { |
330 | grn_id key_domain_id; |
331 | void *key; |
332 | unsigned int key_size; |
333 | grn_mrb_value_to_raw_data_buffer buffer; |
334 | |
335 | key_domain_id = table->header.domain; |
336 | grn_mrb_value_to_raw_data_buffer_init(mrb, &buffer); |
337 | grn_mrb_value_to_raw_data(mrb, "key" , mrb_key, key_domain_id, |
338 | &buffer, &key, &key_size); |
339 | grn_table_delete(ctx, table, key, key_size); |
340 | grn_mrb_value_to_raw_data_buffer_fin(mrb, &buffer); |
341 | grn_mrb_ctx_check(mrb); |
342 | return mrb_nil_value(); |
343 | } |
344 | |
345 | mrb_expression = grn_mrb_options_get_lit(mrb, mrb_options, "expression" ); |
346 | if (!mrb_nil_p(mrb_expression)) { |
347 | grn_obj *expression; |
348 | grn_obj *selected_records; |
349 | grn_table_cursor *cursor; |
350 | |
351 | expression = DATA_PTR(mrb_expression); |
352 | selected_records = grn_table_select(ctx, table, expression, NULL, GRN_OP_OR); |
353 | grn_mrb_ctx_check(mrb); |
354 | cursor = grn_table_cursor_open(ctx, selected_records, |
355 | NULL, 0, |
356 | NULL, 0, |
357 | 0, -1, 0); |
358 | if (cursor) { |
359 | while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) { |
360 | grn_id *id; |
361 | grn_table_cursor_get_key(ctx, cursor, (void **)&id); |
362 | grn_table_delete_by_id(ctx, table, *id); |
363 | } |
364 | grn_table_cursor_close(ctx, cursor); |
365 | } |
366 | grn_mrb_ctx_check(mrb); |
367 | |
368 | return mrb_nil_value(); |
369 | } |
370 | |
371 | mrb_raisef(mrb, E_ARGUMENT_ERROR, |
372 | "must have :id, :key or :expression: %S" , |
373 | mrb_options); |
374 | |
375 | return mrb_nil_value(); |
376 | } |
377 | |
378 | static mrb_value |
379 | mrb_grn_table_truncate(mrb_state *mrb, mrb_value self) |
380 | { |
381 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
382 | grn_obj *table; |
383 | |
384 | table = DATA_PTR(self); |
385 | grn_table_truncate(ctx, table); |
386 | grn_mrb_ctx_check(mrb); |
387 | return mrb_nil_value(); |
388 | } |
389 | |
390 | static mrb_value |
391 | mrb_grn_table_apply_expression(mrb_state *mrb, mrb_value self) |
392 | { |
393 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
394 | mrb_value mrb_output_column; |
395 | mrb_value mrb_expression; |
396 | grn_obj *table; |
397 | grn_obj *output_column = NULL; |
398 | grn_obj *expression = NULL; |
399 | |
400 | mrb_get_args(mrb, "oo" , &mrb_output_column, &mrb_expression); |
401 | |
402 | table = DATA_PTR(self); |
403 | output_column = GRN_MRB_DATA_PTR(mrb_output_column); |
404 | expression = GRN_MRB_DATA_PTR(mrb_expression); |
405 | grn_table_apply_expr(ctx, table, output_column, expression); |
406 | grn_mrb_ctx_check(mrb); |
407 | |
408 | return mrb_nil_value(); |
409 | } |
410 | |
411 | static mrb_value |
412 | mrb_grn_table_apply_window_function_raw(mrb_state *mrb, mrb_value self) |
413 | { |
414 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
415 | mrb_value mrb_output_column; |
416 | mrb_value mrb_window_definition; |
417 | mrb_value mrb_window_function_call; |
418 | grn_obj *table; |
419 | grn_obj *output_column = NULL; |
420 | grn_window_definition *window_definition = NULL; |
421 | grn_obj *window_function_call = NULL; |
422 | |
423 | mrb_get_args(mrb, "ooo" , |
424 | &mrb_output_column, |
425 | &mrb_window_definition, |
426 | &mrb_window_function_call); |
427 | |
428 | table = DATA_PTR(self); |
429 | output_column = GRN_MRB_DATA_PTR(mrb_output_column); |
430 | window_definition = GRN_MRB_DATA_PTR(mrb_window_definition); |
431 | window_function_call = GRN_MRB_DATA_PTR(mrb_window_function_call); |
432 | grn_table_apply_window_function(ctx, |
433 | table, |
434 | output_column, |
435 | window_definition, |
436 | window_function_call); |
437 | grn_mrb_ctx_check(mrb); |
438 | |
439 | return mrb_nil_value(); |
440 | } |
441 | |
442 | void |
443 | grn_mrb_table_init(grn_ctx *ctx) |
444 | { |
445 | grn_mrb_data *data = &(ctx->impl->mrb); |
446 | mrb_state *mrb = data->state; |
447 | struct RClass *module = data->module; |
448 | struct RClass *object_class = data->object_class; |
449 | struct RClass *klass; |
450 | |
451 | klass = mrb_define_class_under(mrb, module, "Table" , object_class); |
452 | MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA); |
453 | |
454 | mrb_define_method(mrb, klass, "[]" , |
455 | mrb_grn_table_array_reference, MRB_ARGS_REQ(1)); |
456 | mrb_define_method(mrb, klass, "id?" , |
457 | mrb_grn_table_is_id, MRB_ARGS_REQ(1)); |
458 | |
459 | mrb_define_method(mrb, klass, "find_column" , |
460 | mrb_grn_table_find_column, MRB_ARGS_REQ(1)); |
461 | mrb_define_method(mrb, klass, "column_ids" , |
462 | mrb_grn_table_get_column_ids, MRB_ARGS_NONE()); |
463 | |
464 | mrb_define_method(mrb, klass, "create_column" , |
465 | mrb_grn_table_create_column, MRB_ARGS_REQ(3)); |
466 | |
467 | mrb_define_method(mrb, klass, "locked?" , |
468 | mrb_grn_table_is_locked, MRB_ARGS_NONE()); |
469 | |
470 | mrb_define_method(mrb, klass, "size" , |
471 | mrb_grn_table_get_size, MRB_ARGS_NONE()); |
472 | mrb_define_method(mrb, klass, "empty?" , |
473 | mrb_grn_table_is_empty, MRB_ARGS_NONE()); |
474 | |
475 | mrb_define_method(mrb, klass, "select" , |
476 | mrb_grn_table_select, MRB_ARGS_ARG(1, 1)); |
477 | mrb_define_method(mrb, klass, "sort_raw" , |
478 | mrb_grn_table_sort_raw, MRB_ARGS_REQ(4)); |
479 | mrb_define_method(mrb, klass, "group_raw" , |
480 | mrb_grn_table_group_raw, MRB_ARGS_REQ(2)); |
481 | |
482 | mrb_define_method(mrb, klass, "delete" , |
483 | mrb_grn_table_delete, MRB_ARGS_REQ(1)); |
484 | |
485 | mrb_define_method(mrb, klass, "truncate" , |
486 | mrb_grn_table_truncate, MRB_ARGS_NONE()); |
487 | |
488 | mrb_define_method(mrb, klass, "apply_expression" , |
489 | mrb_grn_table_apply_expression, MRB_ARGS_REQ(2)); |
490 | mrb_define_method(mrb, klass, "apply_window_function_raw" , |
491 | mrb_grn_table_apply_window_function_raw, MRB_ARGS_REQ(4)); |
492 | } |
493 | #endif |
494 | |