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-1335  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