Navigation Menu

Skip to content

Commit

Permalink
in_records: add
Browse files Browse the repository at this point in the history
  • Loading branch information
kou committed Apr 19, 2017
1 parent f940037 commit 49fe82b
Show file tree
Hide file tree
Showing 8 changed files with 378 additions and 2 deletions.
3 changes: 2 additions & 1 deletion lib/grn_proc.h
@@ -1,6 +1,6 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2009-2016 Brazil
Copyright(C) 2009-2017 Brazil
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -52,6 +52,7 @@ void grn_proc_init_fuzzy_search(grn_ctx *ctx);
void grn_proc_init_highlight(grn_ctx *ctx);
void grn_proc_init_highlight_full(grn_ctx *ctx);
void grn_proc_init_highlight_html(grn_ctx *ctx);
void grn_proc_init_in_records(grn_ctx *ctx);
void grn_proc_init_lock_acquire(grn_ctx *ctx);
void grn_proc_init_lock_clear(grn_ctx *ctx);
void grn_proc_init_lock_release(grn_ctx *ctx);
Expand Down
2 changes: 2 additions & 0 deletions lib/proc.c
Expand Up @@ -3972,4 +3972,6 @@ grn_db_init_builtin_commands(grn_ctx *ctx)
grn_proc_init_object_list(ctx);

grn_proc_init_table_copy(ctx);

grn_proc_init_in_records(ctx);
}
170 changes: 170 additions & 0 deletions lib/proc/proc_in_records.c
@@ -0,0 +1,170 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Brazil
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "../grn_proc.h"

#include <groonga/plugin.h>

static grn_obj *
func_in_records(grn_ctx *ctx,
int n_args,
grn_obj **args,
grn_user_data *user_data)
{
grn_obj *found;
grn_obj *table;
grn_obj columns;
int i;

found = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_BOOL, 0);
if (!found) {
return NULL;
}
GRN_BOOL_SET(ctx, found, GRN_FALSE);

if (n_args < 3) {
GRN_PLUGIN_ERROR(ctx,
GRN_INVALID_ARGUMENT,
"in_records(): wrong number of arguments (%d for 3..)",
n_args);
return found;
}

if ((n_args % 2) != 1) {
GRN_PLUGIN_ERROR(ctx,
GRN_INVALID_ARGUMENT,
"in_records(): the number of arguments must be odd (%d)",
n_args);
return found;
}

table = args[0];
if (!grn_obj_is_table(ctx, table)) {
grn_obj inspected;
GRN_TEXT_INIT(&inspected, 0);
grn_inspect(ctx, &inspected, table);
GRN_PLUGIN_ERROR(ctx,
GRN_INVALID_ARGUMENT,
"in_records(): the first argument must be a table: <%.*s>",
(int)GRN_TEXT_LEN(&inspected),
GRN_TEXT_VALUE(&inspected));
GRN_OBJ_FIN(ctx, &inspected);
return found;
}

GRN_PTR_INIT(&columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
for (i = 1; i < n_args; i += 2) {
grn_obj *column_name = args[i + 1];
grn_obj *column;

if (!grn_obj_is_text_family_bulk(ctx, column_name)) {
grn_obj inspected;
GRN_TEXT_INIT(&inspected, 0);
grn_inspect(ctx, &inspected, table);
GRN_PLUGIN_ERROR(ctx,
GRN_INVALID_ARGUMENT,
"in_records(): "
"the %dth argument must be column name as string: "
"<%.*s>",
i + 1,
(int)GRN_TEXT_LEN(&inspected),
GRN_TEXT_VALUE(&inspected));
GRN_OBJ_FIN(ctx, &inspected);
goto exit;
}

column = grn_obj_column(ctx, table,
GRN_TEXT_VALUE(column_name),
GRN_TEXT_LEN(column_name));
if (!column) {
grn_obj inspected;
GRN_TEXT_INIT(&inspected, 0);
grn_inspect(ctx, &inspected, table);
GRN_PLUGIN_ERROR(ctx,
GRN_INVALID_ARGUMENT,
"in_records(): "
"the %dth argument must be existing column name: "
"<%.*s>",
i + 1,
(int)GRN_TEXT_LEN(&inspected),
GRN_TEXT_VALUE(&inspected));
GRN_OBJ_FIN(ctx, &inspected);
goto exit;
}
GRN_PTR_PUT(ctx, &columns, column);
}

{
grn_obj column_value;

GRN_VOID_INIT(&column_value);
GRN_TABLE_EACH_BEGIN(ctx, table, cursor, id) {
grn_bool found_record = GRN_TRUE;

for (i = 1; i < n_args; i += 2) {
grn_obj *value = args[i];
grn_obj *column = GRN_PTR_VALUE_AT(&columns, (i - 1) / 2);

if (grn_obj_is_data_column(ctx, column)) {
grn_bool found_value = GRN_FALSE;

GRN_BULK_REWIND(&column_value);
grn_obj_get_value(ctx, column, id, &column_value);

found_value = grn_operator_exec_equal(ctx, value, &column_value);
if (ctx->rc != GRN_SUCCESS) {
found_record = GRN_FALSE;
break;
}

if (!found_value) {
found_record = GRN_FALSE;
break;
}
} else {
found_record = GRN_FALSE;
break;
}
}

if (found_record) {
GRN_BOOL_SET(ctx, found, GRN_TRUE);
break;
}
} GRN_TABLE_EACH_END(ctx, cursor);
GRN_OBJ_FIN(ctx, &column_value);
}

exit :
for (i = 1; i < n_args; i += 2) {
grn_obj *column = GRN_PTR_VALUE_AT(&columns, (i - 1) / 2);
if (column->header.type == GRN_ACCESSOR) {
grn_obj_unlink(ctx, column);
}
}
GRN_OBJ_FIN(ctx, &columns);

return found;
}

void
grn_proc_init_in_records(grn_ctx *ctx)
{
grn_proc_create(ctx, "in_records", -1, GRN_PROC_FUNCTION,
func_in_records, NULL, NULL, 0, NULL);
}
3 changes: 2 additions & 1 deletion lib/proc/sources.am
Expand Up @@ -3,6 +3,8 @@ libgrnproc_la_SOURCES = \
proc_config.c \
proc_dump.c \
proc_fuzzy_search.c \
proc_highlight.c \
proc_in_records.c \
proc_lock.c \
proc_object.c \
proc_object_inspect.c \
Expand All @@ -11,6 +13,5 @@ libgrnproc_la_SOURCES = \
proc_schema.c \
proc_select.c \
proc_snippet.c \
proc_highlight.c \
proc_table.c \
proc_tokenize.c
84 changes: 84 additions & 0 deletions test/command/suite/select/function/in_records/multiple.expected
@@ -0,0 +1,84 @@
plugin_register functions/time
[[0,0.0,0.0],true]
table_create Users TABLE_HASH_KEY ShortText
[[0,0.0,0.0],true]
table_create Tags TABLE_HASH_KEY ShortText
[[0,0.0,0.0],true]
table_create Reports TABLE_NO_KEY
[[0,0.0,0.0],true]
column_create Reports user COLUMN_SCALAR Users
[[0,0.0,0.0],true]
column_create Reports tag COLUMN_SCALAR Tags
[[0,0.0,0.0],true]
column_create Reports day COLUMN_SCALAR Time
[[0,0.0,0.0],true]
table_create Logs TABLE_NO_KEY
[[0,0.0,0.0],true]
column_create Logs user COLUMN_SCALAR Users
[[0,0.0,0.0],true]
column_create Logs tag COLUMN_SCALAR Tags
[[0,0.0,0.0],true]
column_create Logs time COLUMN_SCALAR Time
[[0,0.0,0.0],true]
load --table Reports
[
{"user": "alice", "tag": "tag1", "day": "2017-04-18 00:00:00"},
{"user": "alice", "tag": "tag1", "day": "2017-04-19 00:00:00"},
{"user": "david", "tag": "tag2", "day": "2017-04-20 00:00:00"},
{"user": "david", "tag": "tag3", "day": "2017-04-21 00:00:00"}
]
[[0,0.0,0.0],4]
load --table Logs
[
{"user": "alice", "tag": "tag1", "time": "2017-04-18 11:22:33"},
{"user": "alice", "tag": "tag1", "time": "2017-04-20 11:22:33"},
{"user": "bob", "tag": "tag1", "time": "2017-04-19 11:22:33"},
{"user": "david", "tag": "tag1", "time": "2017-04-19 11:22:33"},
{"user": "david", "tag": "tag2", "time": "2017-04-20 11:22:33"}
]
[[0,0.0,0.0],5]
select Logs --filter 'in_records(Reports, user, "user", tag, "tag", time_classify_day(time), "day")'
[
[
0,
0.0,
0.0
],
[
[
[
2
],
[
[
"_id",
"UInt32"
],
[
"tag",
"Tags"
],
[
"time",
"Time"
],
[
"user",
"Users"
]
],
[
1,
"tag1",
1492482153.0,
"alice"
],
[
5,
"tag2",
1492654953.0,
"david"
]
]
]
]
37 changes: 37 additions & 0 deletions test/command/suite/select/function/in_records/multiple.test
@@ -0,0 +1,37 @@
plugin_register functions/time

table_create Users TABLE_HASH_KEY ShortText
table_create Tags TABLE_HASH_KEY ShortText

table_create Reports TABLE_NO_KEY
column_create Reports user COLUMN_SCALAR Users
column_create Reports tag COLUMN_SCALAR Tags
column_create Reports day COLUMN_SCALAR Time

table_create Logs TABLE_NO_KEY
column_create Logs user COLUMN_SCALAR Users
column_create Logs tag COLUMN_SCALAR Tags
column_create Logs time COLUMN_SCALAR Time

load --table Reports
[
{"user": "alice", "tag": "tag1", "day": "2017-04-18 00:00:00"},
{"user": "alice", "tag": "tag1", "day": "2017-04-19 00:00:00"},
{"user": "david", "tag": "tag2", "day": "2017-04-20 00:00:00"},
{"user": "david", "tag": "tag3", "day": "2017-04-21 00:00:00"}
]

load --table Logs
[
{"user": "alice", "tag": "tag1", "time": "2017-04-18 11:22:33"},
{"user": "alice", "tag": "tag1", "time": "2017-04-20 11:22:33"},
{"user": "bob", "tag": "tag1", "time": "2017-04-19 11:22:33"},
{"user": "david", "tag": "tag1", "time": "2017-04-19 11:22:33"},
{"user": "david", "tag": "tag2", "time": "2017-04-20 11:22:33"}
]

select Logs \
--filter 'in_records(Reports, \
user, "user", \
tag, "tag", \
time_classify_day(time), "day")'
57 changes: 57 additions & 0 deletions test/command/suite/select/function/in_records/one.expected
@@ -0,0 +1,57 @@
table_create Users TABLE_HASH_KEY ShortText
[[0,0.0,0.0],true]
table_create Reports TABLE_NO_KEY
[[0,0.0,0.0],true]
column_create Reports user COLUMN_SCALAR Users
[[0,0.0,0.0],true]
table_create Logs TABLE_NO_KEY
[[0,0.0,0.0],true]
column_create Logs user COLUMN_SCALAR Users
[[0,0.0,0.0],true]
load --table Reports
[
{"user": "alice"},
{"user": "david"}
]
[[0,0.0,0.0],2]
load --table Logs
[
{"user": "alice"},
{"user": "bob"},
{"user": "chris"},
{"user": "david"}
]
[[0,0.0,0.0],4]
select Logs --filter 'in_records(Reports, user, "user")'
[
[
0,
0.0,
0.0
],
[
[
[
2
],
[
[
"_id",
"UInt32"
],
[
"user",
"Users"
]
],
[
1,
"alice"
],
[
4,
"david"
]
]
]
]

0 comments on commit 49fe82b

Please sign in to comment.