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
35static mrb_value
36mrb_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
69static mrb_value
70mrb_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
90static mrb_value
91mrb_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
109static mrb_value
110mrb_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
141static mrb_value
142mrb_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
167static mrb_value
168mrb_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
179static mrb_value
180mrb_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
191static mrb_value
192mrb_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
203static mrb_value
204mrb_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
242static mrb_value
243mrb_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
276static mrb_value
277mrb_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
308static mrb_value
309mrb_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
378static mrb_value
379mrb_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
390static mrb_value
391mrb_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
411static mrb_value
412mrb_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
442void
443grn_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